Educational Codeforces Round 122

Posted on 2022-02-08 17:04  Capterlliar  阅读(26)  评论(0编辑  收藏  举报

A. Div. 7

题意:给出一个数,要求在改动最少数字的情况下,使其成为7的倍数。

解:7的倍数,每十个数里肯定有一个。暴力即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
int n,k;
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        if(n%7==0) {
            printf("%d\n",n);
            continue;
        }
        int down=n/10*10;
        for(int i=down;i<down+10;i++) {
            if (i % 7 == 0) {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}
View Code

B - Minority

题意:给出一个01串,可以从中选择一个子数组,删去0和1中数字个数少的那一方,操作一次,问最多删除多少数字。

解:全选上,如果个数相等那随便减一个。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define maxn 100005
#define maxm 200005
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
char s[maxx];
int n;
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",s+1);
        n= strlen(s+1);
        int ans=0,num0=0,num1=0;
        for(int i=1;i<=n;i++){
            if(s[i]=='0') num0++;
            else num1++;
        }
        if(num0!=num1) ans=min(num0,num1);
        else ans=num0-1;
        printf("%d\n",ans);
    }
    return 0;
}
View Code

C - Kill the Monster

题意:你有hc点血,dc点攻;怪物有hm点血,dm点攻。有k次机会,每次可以选择加a点血或者w点攻。你先手,轮着打对方,血线降到0及以下输,问你能不能赢。

解:一开始看错了。。。还以为给怪物加血。治好眼睛后列了个式子,重点在血和攻上怎么分配。打开题目一看k一共就2e5,太好了枚举吧。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 200005
#define maxn 100005
#define maxm 200005
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
ll hc,dc,hm,dm;
ll k,w,a;
signed main() {
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld%lld%lld",&hc,&dc,&hm,&dm);
        scanf("%lld%lld%lld",&k,&w,&a);
        ll c,m;
        int flag=0;
        for(int i=0;i<=k;i++){
            ll h=hc+a*i;
            ll d=dc+w*(k-i);
            c=h/dm+(h%dm!=0);
            m=hm/d+(hm%d!=0);
            if(c>=m)
                flag=1;
        }
        if(flag)
            printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
View Code

D. Make Them Equal

题意:数组a有n个元素,初始值为1。每次操作可以任选一个正整数x,使a[i]=a[i]+a[i]/x,当a[i]与b[i]相等时,获得价值c[i]。最多执行k次操作,求获得最大价值。

解:目测用这种方法可以将1变成任意一个数。如果求出最小步数,那跑一遍背包就完了。现在来求最小步数。一开始贪心,WA掉了。一个数能变成另外几个数,显然应该用最短路。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define maxx 1000005
#define maxn 1005
#define eps 0.00000001
#define inf 0x7fffffff
#define mod 998244353
//#define int long long
int n,k;
int b[maxn],c[maxn],w[maxn];
int vis[maxn]={0};
int dp[maxx]={0};
void spfa(){
    for(int i=1;i<=1000;i++)
        w[i]=inf;
    queue<int> q;
    q.push(1);
    w[1]=0;vis[1]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        vis[now]=0;
        for(int i=1;i<=now;i++){
            int to=now/i+now;
            if(w[to]>w[now]+1){
                w[to]=w[now]+1;
                if(!vis[to]){
                    q.push(to);
                    vis[to]=1;
                }
            }
        }
    }
}
signed main() {
    int T;
    scanf("%d",&T);
    spfa();
    while(T--){
        scanf("%d%d",&n,&k);
        for(int i=0;i<=k;i++)
            dp[i]=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&c[i]);
        for(int i=1;i<=n;i++) {
            for (int j = k; j >= w[b[i]]; j--)
                dp[j]=max(dp[j],dp[j-w[b[i]]]+c[i]);
        }
        printf("%d\n",dp[k]);
    }
    return 0;
}
View Code

E. Spanning Tree Queries

题意:给出一张图和k个询问x,对于每个询问,求将其所有边变为 |wi-x| 后的最小生成树。

解:显然对于每个询问都求一边会T。但是最小生成树好像没什么别的算法,那就从询问下手。对于原来的生成树,现在加入一个x,假设小于x的边有 x1 条,大于x的边有 x2 条,原边权和对应为 s1 + s2 ,现对应和为 s1 - s2 + ( x2 - x1 ) * x ,也就是说,x变化后最小生成树的选择与x1和x2有关,也就是x在原最小生成树中的位置。现在生成次数与变动次数有关,考虑生成次数。k最大到1e7,w最大到1e8,数据类似随机生成,也就是说变动次数不会太大,可以做(但我不会算)。但是这个思路代码贼难写,看了别人解法。大佬直接考虑边,对于两条边a和b,x<(a+b)/2+1 时生成树不变,反之需要重新算。也就是说,先把所有会导致变动的点算出来,会好写很多。