Educational Codeforces Round 121

Posted on 2022-01-19 16:09  Capterlliar  阅读(41)  评论(0编辑  收藏  举报

本来准备做一整套的……但太阳这么好为什么不出去溜溜弯呢。

 A. Equidistant Letters

题意:给出一串字母,每种字母要求间隔相等,输出一种可能的结论。

解:间隔相等,那连续输出就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 2005
#define eps 0.00000001
#define inf 0x3f
//#define int long long
char a[maxx];
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        int num[30]={0};
        scanf("%s",a);
        for(int i=0;i<strlen(a);i++)
            num[a[i]-'a']++;
        for(int i=0;i<26;i++){
            for(int j=0;j<num[i];j++)
                printf("%c",i+'a');
        }
        printf("\n");
    }
    return 0;
}
View Code

B. Minor Reduction

题意:给出一串很长的数,从中挑出两个数把它们换成它们的和。执行一次这样的操作,求获得新串的最大值。

解:可以证明将两个数替换为它们的和总会变小。那么我们希望变小的在最低位,同时它加完还是个两位数,不然少一位会变得更小。从低位向高位遍历,碰到相加大于等于十替换。如果不存在这样的两个数,那么将开头两个数合起来,虽然少了一位,但最高位最大。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define eps 0.00000001
#define inf 0x3f
//#define int long long
char s[maxx];
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        int flag=0;
        for(int i=strlen(s);i>0;i--){
            int t=s[i]-'0'+s[i-1]-'0';
            if(t>9){
                s[i]=t%10+'0';
                s[i-1]=t/10+'0';
                flag=1;
                break;
            }
        }
        if(!flag){
            s[1]=s[0]-'0'+s[1];
            printf("%s\n",s+1);
        }
        else
            printf("%s\n",s);
    }
    return 0;
}
View Code

C. Monsters And Spells

题意:打怪物。第i个怪物只在 k时刻出现,血量为 hi 。每个时刻初始伤害为1,如果连续蓄力a个时刻,伤害可以累积到a。求每个时刻能打出伤害的最小和。

解:如果第 k时刻要打血量为 hi 的怪,那他在 k- hi + 1时刻就要开始蓄力。于是这道题转换成了讨厌的区间合并问题。抄板子吧。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 105
#define eps 0.00000001
#define inf 0x3f
//#define int long long
int n;
int k[maxx]={0},h[maxx]={0};
int s;
ll f(ll x){
    return (1+x)*x/2;
}
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&k[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&h[i]);
        vector<pair<ll,ll> > v;
        for(int i=1;i<=n;i++) {
            s = k[i] - h[i] + 1;
            v.push_back(make_pair(s,k[i]));
        }
        sort(v.begin(),v.end());
        ll st = -1, ed = -1,ans=0;
        for(auto i : v){
            if(ed < i.first){
                if(st != -1)
                    ans+=f(ed-st+1);
                st = i.first, ed = i.second;
            }
            else ed = max(ed, i.second);  //有交集
        }
        ans+=f(ed-st+1);
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

D. Martial Arts Tournament

题意:要将n个选手分为三个重量级,同时希望每个等级的人数刚好能产生一名冠军,也就是2的幂。分级标准是选两个数x、y,分为 [...,x), [x,y), [y,...)三组。求至少添加多少人,每组的人数刚好为2的幂。

解:枚举x和y显然会炸,那就枚举最后的人数为多少。假设最终第一组有 2a 人,第三组有 2b人,第二组有 n - 2a - 2b 人,再分别算出距离目标差多少,暴力求最小值即可。中间用前缀和以及二分优化一下,每次都想吐槽没找到为什么不返回-1。。。虽然和这题没关系。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define eps 0.00000001
#define inf 0x7fffffff
//#define int long long
int n;
int a[maxx];
int b[50];
ll pre[maxx]={0},suf[maxx]={0};
int cnt1,cnt2;
ll f(int x){
    int t= lower_bound(b,b+30,x)-b;
    return b[t]-x;
}
ll check(int x,int y){
    int a1= upper_bound(pre+1,pre+1+cnt1,x)-pre-1;
    int a2= upper_bound(suf+1,suf+1+cnt2,y)-suf-1;
    int num1=pre[a1],num2=suf[a2];
    if(a1==0)
        num1=0;
    if(a2==0)
        num2=0;
    int num3=n-num1-num2;
    ll res=f(num1)+f(num2)+f(num3);
    return res;
}
signed main() {
    int T;
    scanf("%d",&T);
    b[0]=1;
    for(int i=1;i<=30;i++)
        b[i]=(b[i-1]<<1);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        cnt1=0;
        ll temp=1;
        for(int i=2;i<=n;i++){
            if(a[i]==a[i-1])
                temp++;
            if(a[i]!=a[i-1]||i==n){
                cnt1++;
                pre[cnt1]=pre[cnt1-1]+temp;
                temp=1;
            }
        }
        cnt2=0,temp=1;
        for(int i=n-1;i>=0;i--){
            if(a[i]==a[i+1])
                temp++;
            if(a[i]!=a[i+1]||i==0){
                cnt2++;
                suf[cnt2]=suf[cnt2-1]+temp;
                temp=1;
            }
        }
        ll ans=inf;
        for(int i=0;i<=18;i++){
            for(int j=0;j<=18;j++)
                ans=min(ans, check(b[i],b[j]));
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code