CF #190(DIV2)总结

来源:互联网 发布:cellsens成像软件 编辑:程序博客网 时间:2024/05/21 08:42

首先说说做CF的感受把:大多数是智力题,而且偏向某个方向很严重,而且答案具有开放性,可以有多种解。所以这轮的主题也就是“贪心”。

A. Ciel and Dancing
   这题题目建模,给定一张二部图,左边N各节点,右边M个节点,要求一种连接法连接左右两部,使的所有边的点都有一个是只有一条边的。

   那么贪心思想,首先让n1与所有m结合,然后在用m2与所有n(除了n1之外)相连就行了。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){        if(n <= m){            printf("%d\n",n+m-1);            for(int i=1;i<=m;i++)                printf("1 %d\n",i);            for(int i=2;i<=n;i++)                printf("%d 1\n",i);        }else{            printf("%d\n",n+m-1);            for(int i=1;i<=n;i++)                printf("%d 1\n",i);            for(int i=2;i<=m;i++)                printf("1 %d\n",i);        }    }    return 0;}                                                                                                
B. Ciel and Flowers

题意:有三种方法构成花束,三朵红或者绿或者蓝,还有各种颜色各一朵,先给出三种花朵的数目,求能组成的最多的花束。

贪心:比较几种构成法,求其中那个最多的那种。(想不到我也有今天,对不起勒,题解太简略了,赶时间啊)

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;int main(){    int r,g,b;    while(~scanf("%d%d%d",&r,&g,&b)){        int sum123 = r/3 + g/3 + b/3 + min(r%3,min(g%3,b%3));        int sum12 = r/3 + g/3 + min(r%3,min(g%3,b)) + (b-min(r%3,min(g%3,b)))/3;        int sum23 = g/3 + b/3 + min(g%3,min(b%3,r)) + (r-min(g%3,min(b%3,r)))/3;        int sum13 = r/3 + b/3 + min(r%3,min(b%3,g)) + (g-min(r%3,min(b%3,g)))/3;        int sum1 = r/3 + min(r%3,min(b,g))+(b-min(r%3,min(b,g)))/3+(g-min(r%3,min(b,g)))/3;        int sum2 = g/3 + min(g%3,min(r,b))+(r-min(g%3,min(r,b)))/3+(b-min(g%3,min(r,b)))/3;        int sum3 = b/3 + min(b%3,min(r,g))+(r-min(b%3,min(r,g)))/3+(g-min(b%3,min(r,g)))/3;        int sum = min(r,min(g,b))+(r-min(r,min(g,b)))/3+(g-min(r,min(g,b)))/3+(b-min(r,min(g,b)))/3;        int ans;        ans = max(sum1,sum2);        ans = max(ans,sum3);        ans = max(ans,sum12);        ans = max(ans,sum13);        ans = max(ans,sum23);        ans = max(ans,sum123);        ans = max(ans,sum);        cout<<ans<<endl;    }}

C. Ciel and Robot

题意:给定一个走法序列,只能重复该序列,不能改变顺序,问该走法序列能否帮助机器人走到目标点(a,b )。

首先求出一次走法序列能向右走多少,向上走多少,判断该位移能否满足目标点,如不行,然后枚举走法序列每一步的位移,看看该位移是否满足被目标点整除的情况(大概是这个意思,赶时间啊)

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 106char str[maxn];int main(){    int a,b;    while(~scanf("%d%d",&a,&b)){        getchar();        gets(str);        int len = strlen(str);        int flag = 0;        int x = 0,y = 0;        for(int i=0;i<len&&flag==0;i++){            if(x==a && y==b) flag = 1;            if(str[i]=='U') y++;            if(str[i]=='D') y--;            if(str[i]=='L') x--;            if(str[i]=='R') x++;            if(x==a && y==b) flag = 1;        }        if(flag == 0){            int q=0,p=0;            for(int i=0;i<len&&flag==0;i++){                if(str[i]=='U') q++;                if(str[i]=='D') q--;                if(str[i]=='L') p--;                if(str[i]=='R') p++;                if(x==0 && y==0){                    if(p==a && q==b) flag = 1;                }else if(x==0 && y!=0){                    if(p==a && (b-q)%y==0 && (b-q)/y>=0)                        flag = 1;                }else if(y==0 && x!=0){                    if(q==b && (a-p)%x==0 && (a-p)/x>=0)                        flag = 1;                }else{                    if((a-p)%x==0&&(b-q)%y==0&&(b-q)/y==(a-p)/x&&(a-p)/x>=0)                        flag = 1;                }            }        }        if(flag) puts("Yes");        else puts("No");    }    return 0;}

D. Ciel and Duel

题意:游戏王玩过吧,给定你的攻击怪兽的攻击力,给出对手的攻击性怪兽的攻击力、防守型怪兽的防守力,还可以直接对玩家进行伤害,计算能造成的最多伤害。

首先,将我方怪兽攻击力高低排序,对方怪兽防守力、攻击力分别排序

贪心策略:(1)考虑对玩家进行直接伤害,即用我方怪兽消灭对方所有怪兽,剩余怪兽直接伤害,按照这种理论,我们就需要首先把所有的防守型怪兽消灭,而且是利用最小大过其防守力的怪兽去ATK,然后,如果还有怪兽,就用大过对方攻击型怪兽的最小的攻击力的怪兽消灭对方攻击性怪,最后剩下的怪兽直接攻击。

(2)不考虑直接伤害,那么用最大攻击力的怪去打对方攻击性攻击力最小的怪,如此做,即可。

最后比较两种方法的好坏即可。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 106int n,m;int top1,top2;int a[maxn];bool hash[maxn];int b1[maxn]; //进攻int b2[maxn]; //防守int f1(){    int x1=0,x2=0;    int ret = 0;    memset(hash,false,sizeof(hash));    for(int i=0;i<m&&x2<top2;i++) {        if(hash[i]==false && a[i]>b2[x2]){            hash[i] = true;            x2++;        }    }    for(int i=0;i<m&&x1<top1;i++){ //这里一定是用攻击力小的击败对手atk型怪兽,然后用高攻击的怪直接攻击        if(hash[i]==false && a[i]>=b1[x1]){            ret += a[i] - b1[x1];            x1++;            hash[i] = true;        }    }    if(x2==top2 && x1==top1){        for(int i=0;i<m;i++){            if(hash[i]==false) ret += a[i];        }    }    return ret;}int f2(){    int x1 = 0,x2=0;    int ret = 0;    memset(hash,false,sizeof(hash));    for(int i=m-1;i>=0 && x1<top1;i--){        if(hash[i]==false&&a[i]>=b1[x1]){            ret += a[i] - b1[x1];            x1++;            hash[i]=true;        }    }    for(int i=0;i<m&&x2<top2;i++){        if(hash[i]==false&&a[i]>b2[x2]){            hash[i] = true;            x2++;        }    }    if(x1==top1 && x2==top2){        for(int i=0;i<m;i++){            if(hash[i]==false) ret += a[i];        }    }    return ret;}int main(){    while(~scanf("%d%d",&n,&m)){        getchar();        char cmd[5];        int ss;        top1 = 0,top2 = 0;        for(int i=0;i<n;i++){            scanf("%s%d",cmd,&ss);            if(cmd[0]=='A') b1[top1++] = ss; //进攻            else b2[top2++] = ss; //防守        }        for(int i=0;i<m;i++){            scanf("%d",&a[i]);        }        sort(a,a+m);        sort(b1,b1+top1);        sort(b2,b2+top2);        int sum1 = f1();        int sum2 = f2();        int ans = max(sum1,sum2);        cout<<ans<<endl;    }    return 0;}

E. Ciel the Commander

题意:给定一棵树,要求标级别(A~Z,A最小),相邻两个点级别不能相同,相同级别的两个点之间必有比他们级别大的点,求一种标级方案。

这是最有价值的一道题目,利用自底向上的算法,假设我们已经表记好了子树根节点T1,T2,T3.....TK,如何标记他们的根节点,首先只要有两个子根节点级别相同,则根节点必须大于之,不能出现与子根节点的级别相同的级别。

这里关键技术又变为如何dfs这个树并标记了,有用到了强大的二进制了,只有26个字母么,11111代表用了A~E……,懂了吧。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxm 300006#define maxn 100005typedef struct {    int to,next;}Edge;Edge e[maxm];int head[maxn];int n;int e_cnt;struct Tree{    int stu; //二进制表示使用了哪一种等级,如10代表使用了B等级    int rank; //等级}tree[maxm];bool flag;void init(){    memset(head,-1,sizeof(head));    e_cnt = 0;}void add(int u,int v){    e[e_cnt].to = v;    e[e_cnt].next = head[u];    head[u] = e_cnt;    e_cnt++;}void dfs(int x,int fa){    int stu = 0;    int dub = 0; //度数    for(int i=head[x];i!=-1;i=e[i].next){        int v = e[i].to;        if(v == fa) continue;        dfs(v,x);        dub = max(dub,stu&tree[v].stu);        stu |= tree[v].stu;    }    int &p = tree[x].stu;    p = 1;    while(p<=dub || (p&stu)) p <<= 1;    for(int i=(p<<1);i<(1<<26);i<<=1) if(i&stu) p |= i;    for(int i=0;i<26;i++){        if((1<<i)&tree[x].stu){            tree[x].rank = 26 - i - 1;            if(tree[x].rank<0 || tree[x].rank>26) flag = true;            return ;        }    }}int main(){    while(~scanf("%d",&n)){        memset(tree,0,sizeof(tree));        init();        flag = false;        int u,v;        for(int i=0;i<n-1;i++){            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        dfs(1,0);        if(flag ) cout<<"Impossible!";        else{            for(int i=1;i<=n;i++) cout<<char(tree[i].rank+'A')<<" ";        }        cout<<endl;    }    return 0;}




 

原创粉丝点击