CF #180 (div1)

A. Parity Game

problem:

在一个01串中。可以去掉最前面的一个字符;可以在后面加一个字符,若该串有奇数个‘1’则末尾加字符‘1’否则加‘0’。

问能否把a串变为b串。

think:

如果偶数个‘1’则‘0’可以在结尾任意加。又因为前面随便去掉,所以可以在想要的位置去掉前面的‘1’然后结尾加‘1’。所以偶数(n)个‘1’的串可以变成任意‘1’的个数为(<=n)的串。

如果奇数个‘1’。后面加一个‘1’就变成了上一种情况。所以奇数个'1'的串可以变成任意‘1’的个数为(<=n+1)的串。


B. Fish Weight

problem:

Alice有n个东西,Bob有m个东西。每个东西的大小排序为[1, k]中的一个整数。只是大小定性排序,具体多少不一定。问Alice能不能比Bob多。

think:

从大往小比较,遇到Alice的比Bob的大,那就把Alice的无限变大,所以就是可能。否则就假装他俩一样大,继续比较。必到最后谁最先没了谁就输了。

code:

  1. int main(){  
  2.     int n, m, k;  
  3.     scanf("%d%d%d", &n, &m, &k);  
  4.     for(int i=0; i<n; i++){  
  5.         scanf("%d", &a[i]);  
  6.     }  
  7.     for(int i=0; i<m; i++){  
  8.         scanf("%d", &b[i]);  
  9.     }  
  10.     sort(a, a+n);  
  11.     sort(b, b+m);  
  12.     bool ok = false;  
  13.     for(int i=n-1, j=m-1; i>=0 && j>=0; i--, j--){  
  14.         if(a[i]>b[j]){  
  15.             ok = true;  
  16.             break;  
  17.         }  
  18.         else if(j==0 && i!=0){  
  19.             ok = true;  
  20.             break;  
  21.         }  
  22.         else if(i==0){  
  23.             ok = false;  
  24.             break;  
  25.         }  
  26.     }  
  27.     if(ok) puts("YES");  
  28.     else puts("NO");  
  29.     return 0;  
  30. }  


C. Splitting the Uniqueness

problem:

给出一个长度为n的s非负数序列,里面每个数字都不一样,能否有两个长度为n的非负数序列a和b,a[i]+b[i]=s[i],且有不少于2/3的数字都不一样。

think:

请注意:s本身是每个元素都不一样的。排序后从后后2/3个,从0开始给a一个给b一个。如:“0 1 a b c d” 把“a b c d”变成“0 b 1 d-1”和“a 0 c-1 1”。因为d 比b至少大2,所以d-1>b. 因为是后2/3所以b>k(k为需要变化的个数的一半减1,在这里,需要变化的个数为4,一半为2,减1为1)

code:

  1. struct point {  
  2.     int s, id;  
  3. }p[N];  
  4. int a[N], b[N];  
  5. bool cmp(point x, point y){  
  6.      return x.s<y.s;  
  7. }  
  8.   
  9. int main(){  
  10.     int n;  
  11.     scanf("%d", &n);  
  12.     for(int i=0; i<n; i++){  
  13.         scanf("%d", &p[i].s);  
  14.         p[i].id = i;  
  15.     }  
  16.     int m = n-(n+2)/3;  
  17.     sort(p, p+n, cmp);  
  18.     for(int i=n-m, j=0; i<n; i++, j++){  
  19.         int id = p[i].id;  
  20.         if(j&1){  
  21.             b[id] = j/2;  
  22.             a[id] = p[i].s-j/2;  
  23.         }  
  24.         else{  
  25.             a[id] = j/2;  
  26.             b[id] = p[i].s-j/2;  
  27.         }  
  28.     }  
  29.     for(int i=0; i<n-m; i++){  
  30.         int id = p[i].id;  
  31.         a[id] = 0;  
  32.         b[id] = p[i].s;  
  33.     }  
  34.     puts("YES");  
  35.     for(int i=0; i<n; i++) printf("%d ", a[i]);  
  36.     puts("");  
  37.     for(int i=0; i<n; i++) printf("%d ", b[i]);  
  38.     puts("");  
  39.     return 0;  
  40. }  


D. Color the Carpet

problem:

给出一张n*m的图表,用不多于k种颜色涂色,使其满足图表中3/4的等于不等于关系。

think:

共有n*(m-1)+m*(n-1)个关系。我们把这个分为两部分n*(m-1)和m*(n-1)。若多的那一部分满足所有关系,少的那一部分满足一半以上的关系,就是可以了。假设n<m,即让n*(m-1)全部满足,就是让同一行的关系都满足。如果只有两个颜色,那么当这一行满足条件时,看与上一行的关系满足的是否过半,若不过半,那么这一行全部换颜色,这样与上一行的关系满足一半以上并且行内依然全部满足。(n>m的话同理)所以颜色两个就够了,当然,要特判k==1的时候。

code:

  1. char a[N][N], b[N][N], c[N][N];  
  2. bool ans[N][N];  
  3.   
  4. int main(){  
  5.     int n, m, k;  
  6.     scanf("%d%d%d", &n, &m, &k);  
  7.     for(int i=0; i<n; i++){  
  8.         scanf("%s", a[i]);  
  9.         if(i<n-1) scanf("%s", b[i]);  
  10.     }  
  11.     if(k==1){  
  12.         int t=0;  
  13.         for(int i=0; i<n; i++){  
  14.             for(int j=0; j<m-1; j++) t+=(a[i][j]=='E'?1:0);  
  15.             if(i==n-1) break;  
  16.             for(int j=0; j<m; j++) t+=(b[i][j]=='E'?1:0);  
  17.         }  
  18.         if(t*4>=3*(n*(m-1)+m*(n-1))){  
  19.             puts("YES");  
  20.             for(int i=0; i<n; i++){  
  21.                 printf("1");  
  22.                 for(int j=1; j<m; j++) printf(" 1");  
  23.                 puts("");  
  24.             }  
  25.         }  
  26.         else puts("NO");  
  27.         return 0;  
  28.     }  
  29.     if(m>=n){  
  30.         for(int i=0; i<n; i++){  
  31.             ans[i][0] = 0;  
  32.             for(int j=1; j<m; j++)  
  33.                 ans[i][j] = ans[i][j-1]^(a[i][j-1]=='N');  
  34.             int t=0;  
  35.             if(i==0) continue;  
  36.             for(int j=0; j<m; j++)  
  37.                 t+=((ans[i-1][j]^(b[i-1][j]=='N'))==ans[i][j])?1:0;  
  38.             if(t*2<m){  
  39.                 for(int j=0; j<m; j++) ans[i][j] = !ans[i][j];  
  40.             }  
  41.         }  
  42.     }  
  43.     else{  
  44.         for(int j=0; j<m; j++){  
  45.             ans[0][j] = 0;  
  46.             for(int i=1; i<n; i++)  
  47.                 ans[i][j] = ans[i-1][j]^(b[i-1][j]=='N');  
  48.             int t=0;  
  49.             if(j==0) continue;  
  50.             for(int i=0; i<n; i++){  
  51.                 t+=((ans[i][j-1]^(a[i][j-1]=='N'))==ans[i][j])?1:0;  
  52.             }  
  53.             if(t*2<n){  
  54.                 for(int i=0; i<n; i++) ans[i][j] = !ans[i][j];  
  55.             }  
  56.         }  
  57.     }  
  58.     puts("YES");  
  59.     for(int i=0; i<n; i++){  
  60.         printf("%c""12"[ans[i][0]]);  
  61.         for(int j=1; j<m; j++) printf(" %c""12"[ans[i][j]]);  
  62.         puts("");  
  63.     }  
  64.     return 0;  
  65. }  



E. Mystic Carvings

problem:

一个圆上依次有1~2*n的数字。每个数字都有且只有另一个数字与他相连。选出三条线,使得每条线的两端之间隔的最少点(只包括被选择的6个点)的个数相等。

think:

六个点三条边有以下五种可能:


(用PPT画的图不好看。。)明显只有第1个和第4个可以。用间接法求。

令a,b为一条线的两个端点且a<b。令x为两端点都在(a, b)之间的线的个数。令y为另一侧的线的个数。令z为与之相交的线的个数。那么上图第三个就是x*y. 上图第二个和第五个就是z*(x+y),但是这里算重复了,最后/2. 求x可以用树状数组来维护。知道x了,则z=b-a-1-x*2. 又x+y+z+1=n.

code:

  1. const int N = 200009;  
  2. int a[N], b[N], c[N], p[N];  
  3. int n, m;  
  4.   
  5. inline int lowbit(int f){  
  6.     return f&(-f);  
  7. }  
  8.   
  9. int sum(int f){  
  10.     int ans = 0;  
  11.     for(int i=f; i>0; i-=lowbit(i)){  
  12.         ans += c[i];  
  13.     }  
  14.     return ans;  
  15. }  
  16.   
  17. void add(int f, int g){  
  18.     for(int i=f; i<=m; i+=lowbit(i)){  
  19.         c[i] += g;  
  20.     }  
  21. }  
  22.   
  23. int main(){  
  24.     scanf("%d", &n);  
  25.     m = n*2;  
  26.     for(int i=1; i<=n; i++){  
  27.         scanf("%d%d", &a[i], &b[i]);  
  28.         p[ a[i] ] = b[i];  
  29.         p[ b[i] ] = a[i];  
  30.     }  
  31.     long long a1 = 0;  
  32.     long long a2 = 0;  
  33.     for(int i=1; i<=m; i++){  
  34.         if(p[i]>i) continue;  
  35.         int x = sum(i)-sum(p[i]-1);  
  36.         int z = i-p[i]-1-x*2;  
  37.         add(p[i], 1);  
  38.         long long y = n-1-x-z;  
  39.         a1 += z*(x+y);  
  40.         a2 += x*y;  
  41.     }  
  42.     long long nn = n;  
  43.     long long aa = nn*(nn-1)*(nn-2)/6;  
  44.     cout<<aa-a1/2-a2<<endl;  
  45.     return 0;  
  46. }  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值