其他分享
首页 > 其他分享> > # Educational Codeforces Round 135 (Rated for Div. 2) A-E

# Educational Codeforces Round 135 (Rated for Div. 2) A-E

作者:互联网

Educational Codeforces Round 135 (Rated for Div. 2)

传送门

A

题意:
给定n个颜色的各自的数量,每次可以使用两个不同的颜料,问最后可能剩下哪种颜料,输出任意一个即可。

分析:直接输出个数最多的那个颜料即可

void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    rep(i,1,n) a[i]=read();
    int pos,maxx=-1;
    rep(i,1,n) 
        if(a[i]>maxx) maxx=a[i],pos=i;
    print(pos);pts;
}  

B

题意:
定义一个长度为\(n\)的排列\(p\)的价值如下:
最初价值为0,
如果\(x<p_1\),则\(x=x+p_1\),否则\(x=0\)
如果\(x<p_2\),则\(x=x+p_2\),否则\(x=0\)
.......
如果\(x<p_n\),则\(x=x+p_n\),否则\(x=0\)

你需要找出一个价值最大的长度为n的排列,任意一个即可。

分析:
对于最后一个位置,\(x<p_n\)才能得到尽可能大的值,而\(x\)最大可取到\(p_n-1\),因此最后一位一定是\(n\),而最后一位前的和为\(n-1\),这样价值最大。

此时不妨让最后两位分别为\(n-1,n\),让前面一直相消即可。对于n为偶数,输出\(2,1,4,3....n-2,n-3,n-1,n\),对于n为奇数,观察到\(1,2,3\)后最后价值为0,因此在输出\(1,2,3\)后同偶数情况即可。

void solve(){
    int n;n=read();
    if(n&1){
        rep(i,1,3) print(i),ptc;
        rep(i,4,n-2){
            print(i+1);ptc;print(i);ptc;
            i++;
        }
        print(n-1);ptc;print(n);pts;
    }
    else{
        rep(i,1,n-2){
            print(i+1);ptc;print(i);ptc;
            i++;
        }
        print(n-1);ptc;print(n);pts;
    }
}  

C

题意:
定义\(f(x)\)为\(x\)在十进制下的位数。
现在给你a,b两个数列,一次操作你可以选择两个数列中的一个数\(y\),将其变为\(f(y)\),你的目的是将两个数列所含的数完全相同,求最少操作数。

分析:
注意到\(a_i,b_i \leq 1e9\),因此一个数最多经过两次变换即可得到\(1\)。之后暴力枚举哪些数变即可。

首先将a,b中已经相同的数去掉,他们不需要再动了。随后对剩下的a,b中的数均进行操作,记录答案,此时已经为1位数的数不用再操作;然后再次筛选已经相同的数,对剩下的数进行操作,记录答案,此时已经为1的数不计入操作。

void solve(){
    int n;n=read();
    multiset<int>a,b,c,d;
    rep(i,1,n){
        int x;x=read();a.insert(x);
    }
    rep(i,1,n){
        int x;x=read();
        if(a.find(x)==a.end() )b.insert(x);
        else a.erase(a.find(x));
    }
    int ans=0;
    for(auto x:a) if(x>9) ans++;
    for(auto x:b) if(x>9) ans++;
    for(auto x:a){
        if(x>9)c.insert(f(x));
        else c.insert(x);
    }
    for(auto x:b){
        int y=x>9? f(x):x;
        if(c.find(y)==c.end()) {
            d.insert(y);
        }
        else c.erase(c.find(y));
    }
    for(auto x:c) if(x!=1) ans++;
    for(auto x:d) if(x!=1) ans++;
    print(ans);pts;
}  

D

题意:
给定一个字符串,Alice和Bob进行游戏,两个人各拥有一个初始为空的字符串,每人每次可以从字符串首或尾取一个字符放入自己字符串的头部,问再字符串取完后是Alice胜还是Bob胜还是平局。

分析:
首先对于取的最终状态是两个字符,此时因为Alice先取,所以终态只有Alice胜和平局,故最后结果也如此。此处直接\(n^2\)记忆化搜索,枚举所有情况,看Alice是否有机会取胜即可。

int n;
char s[maxn];
int mp[maxn][maxn];
int dfs(int l,int r){
    if(l==r-1) {
        if(s[l]==s[r]) return 0;
        return 1;
    }
    if(mp[l][r]!=-1) return mp[l][r];
    int l1=dfs(l+1,r-1)|(s[l]<s[r]),l2=dfs(l+2,r)|(s[l]<s[l+1]);
    int r1=dfs(l+1,r-1)|(s[r]<s[l]),r2=dfs(l,r-2)|(s[r]<s[r-1]);
    int L=l1&l2,R=r1&r2;
    return mp[l][r]=L|R;
}
 
void solve(){
    cin>>(s+1);
    n=strlen(s+1);
    rep(i,1,n) rep(j,1,n) mp[i][j]=-1;
    if(dfs(1,n)) puts("Alice");
    else puts("Draw");
}  

E

题意:
有n个人前来吃饭,你可以给每个人放辣椒或黑胡椒,第\(i\)个人放辣椒或黑胡椒可分别获得\(a_i,b_i\)的美味值,你希望n个人获得的总的美味值最大,为此你将去商店去买这两种调味料。

一共有m家商店,对于第\(i\)家店,它们辣椒和黑胡椒均是按包麦,即一包辣椒有\(x_i\)份辣椒,一包黑胡椒有\(y_i\),你一次只能去一家商店去买,且买的时候总份数必须为n,即不能买多,\(x*x_i+y*y_i=n\)。求问对于每一家店,在该店购买调味时,可以带来的最大美味值,或者在这家店不能恰好买\(n\)份调味,输出\(-1\)

分析:

首先对于n个人的美味值,最大情况每个人都吃到了\(a_i,b_i\)中较大的那个,此时我们将人分为三类,\(a_i>b_i,a_i<b_i,a_i=b_i\),记它们人数分别为\(sa,sb,c\),当辣椒数量z在\([sa,sa+c]\)之间时,美味均可取最大值,否则当\(z>sa+c\)时,在\(a_i<b_i\)这一类中选较小的\(b_i-a_i\)来弥补差值,\(z<sa\)时同理,这里前缀和优化即可。因此当辣椒数量确定时,可以\(O(1)\)确定最大美味值,同时美味值关于辣椒数量的函数图像是一个梯形,即先上升,再不变,再下降,当\(c=0\)时,不变的区间退化为点。

对于去某一家点购买时,要满足\(x*x_i+y*y_i=n\),这是扩展欧几里得问题,直接求解即可,存在无解情况。
当有解时,求出特解后向一般解扩展,此时一般解需向梯形图像中间处靠,分类讨论即可。

具体实现时,将特解先转换为非负解,否则不合法。随后分为三类:
\(1. sa\leq x*x_i \leq sa+c\) 此时美味值直接达到最大,后续不用再进行
\(2. x*x_i< sa\),此时将x扩大至\(x*x_i\)最接近\(sa\)处,进行统计,然后越过\(sa\)再次统计
\(3. x*x_i>sa+c\),此时将x缩小至\(x*x_i\)最接近\(sa+c\)处,进行统计,然后越过\(sa+c\)再次统计

整个过程中,需要注意\(x<0\)和\(x*x_i>n\)的特殊情况,同时\(long long\)不能少。

ll gcd(ll a,ll b){return (!b)? a:gcd(b,a%b);}
void exgcd(ll &x,ll &y,ll a,ll b){
    if(b==0){x=1;y=0;return;}
    exgcd(x,y,b,a%b);
    ll temp=x;       
    x=y;y=temp-(a/b)*y;
    return;
}
ll a[maxn],b[maxn];
int c=0;
int sa=0,sb=0;
ll sum=0;
void gett(ll& ans,ll z){
    if(z>sa+c) ans=max(sum-b[z-sa-c],ans);
    else if(z<sa) ans=max(sum-a[sa-z],ans); 
    else ans=sum;
}
void solve(){
    ll n;n=read();
    rep(i,1,n){
        int x,y;scanf("%d %d",&x,&y);
        sum+=max(x,y);
        if(x>y) a[++sa]=(x-y);
        else if(x<y) b[++sb]=(y-x);
        else c++;
    }
    sort(a+1,a+1+sa);
    sort(b+1,b+1+sb);
    rep(i,1,sa) a[i]+=a[i-1];
    rep(i,1,sb) b[i]+=b[i-1];
    int m=read();
    while(m--){
        ll u,v;scanf("%lld %lld",&u,&v);
        ll w=gcd(u,v);
        if(n%w!=0) {puts("-1");continue;}
        ll x,y;
        exgcd(x,y,u,v);     
        x=x*n/w,y=y*n/w;
        ll t=v/w;
        if(x<0){
            int tep= (-x+t-1)/t;
            x+=tep*t;
            y-=tep*u/w;
        }
        if(y<0){
            int tep= (-y+u/w-1)/(u/w);
            x-=tep*t;
            y+=tep*u/w;
        }
        if(x<0||y<0) {puts("-1");continue;}
        ll ans=0,z=x*u;
        gett(ans,z);
        if(ans==sum){print(ans);pts;continue;}
        //向下
        if(z>sa+c){
            int tmp=z-sa-c;tmp/=(t*u);
            x-=tmp*t;z=x*u;
            if(z<=n&&x>=0) gett(ans,z);
            x-=t;z=x*u;
            if(z<=n&&x>=0) gett(ans,z);
        }
        if(ans==sum){print(ans);pts;continue;}
        //向上
        if(z<sa){
            int tmp=sa-z;tmp/=(t*u);
            x+=tmp*t;z=x*u;
            if(z<=n&&x>=0) gett(ans,z);
            x+=t;z=x*u;
            if(z<=n&&x>=0) gett(ans,z);
        }
        print(ans);pts;
    }
}  

标签:Educational,Rated,int,ll,Codeforces,ans,print,sa,rep
来源: https://www.cnblogs.com/Mr-leng/p/16674031.html