• Codeforces Round #779 (Div. 2)


    A. Marin and Photoshoot

    题目链接:Problem - A - Codeforces

    样例输入: 

    1. 9
    2. 3
    3. 000
    4. 3
    5. 001
    6. 3
    7. 010
    8. 3
    9. 011
    10. 3
    11. 100
    12. 3
    13. 101
    14. 3
    15. 110
    16. 3
    17. 111
    18. 19
    19. 1010110000100000101

    样例输出:

    1. 4
    2. 2
    3. 1
    4. 0
    5. 2
    6. 0
    7. 0
    8. 0
    9. 17

    题意:给定一个长度为n的01字符串,问我们至少要在这个区间内插入多少个1字符才能使得对于任意区间均有字符0的个数小于等于字符1的个数。

    分析:通过分析不难发现对于任意两个相邻(此处的相邻不考虑中间的1)的0我们都要保证其之间至少要有2个1,简单模拟一下就能发现这个规律,然后我们按照这个方法分析一下每两个相邻的0然后统计一下需要插入的1即可。

    1. #include<iostream>
    2. #include<algorithm>
    3. #include<cstring>
    4. #include<cstdio>
    5. #include<cmath>
    6. #include<vector>
    7. #include<queue>
    8. using namespace std;
    9. const int N=2e5+10;
    10. char s[N];
    11. int main()
    12. {
    13. int T;
    14. cin>>T;
    15. while(T--)
    16. {
    17. int n;
    18. scanf("%d",&n);
    19. int ans=0;
    20. scanf("%s",s+1);
    21. int last=0;
    22. for(int i=1;i<=n;i++)
    23. {
    24. if(s[i]=='0')
    25. {
    26. if(last) ans+=max(2-(i-last-1),0);
    27. last=i;
    28. }
    29. }
    30. printf("%d\n",ans);
    31. }
    32. return 0;
    33. }

    B. Marin and Anti-coprime Permutation

    题目链接:Problem - B - Codeforces

    题意: 给定一个n,p1~pn为1~n的一个排列,问有多少个排列满足gcd(1⋅p1,2⋅p2,…,n⋅pn)>1,通过样例我们能够发现当n为奇数时,最大公约数一定是1,当n为偶数时,我们存在那种最大公约数大于1的情况,但是不存在最大公约数大于等于3的情况。现在我们就来分析一下n为偶数时最大公约数为2的方案数,那么就是一个奇数和一个偶数进行组合,总共有n/2个偶数,n/2个奇数,那么总的排列方案数就是(n/2)!*(n/2)!.

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace std;
    9. const int N=2e5+10,mod=998244353;
    10. int main()
    11. {
    12. int T;
    13. cin>>T;
    14. while(T--)
    15. {
    16. int n;
    17. scanf("%d",&n);
    18. if(n&1) puts("0");
    19. else
    20. {
    21. long long t=n/2;
    22. long long ans=1;
    23. for(int i=t;i>=1;i--)
    24. ans=ans*i%mod*i%mod;
    25. printf("%lld\n",ans);
    26. }
    27. }
    28. return 0;
    29. }

    C. Shinju and the Lost Permutation

    题目链接:Problem - C - Codeforces

    样例输入: 

    1. 6
    2. 1
    3. 1
    4. 2
    5. 1 2
    6. 2
    7. 2 2
    8. 6
    9. 1 2 4 6 3 5
    10. 6
    11. 2 3 1 2 3 4
    12. 3
    13. 3 2 1

    样例输出:

    1. YES
    2. YES
    3. NO
    4. NO
    5. YES
    6. NO

    题意:有一个1~n的排列p1~pn,但是我们不知道这个排列是什么,现在有数组b[i][]=

    [pn−i+1,…,pn,p1,p2,…,pn−i],也就是对原数组进行循环右移i次得到的结果,现在定义一个数组c[],其中对于数组b[i][],c[i]就是max(b[i][1~i]),c数组的权值定义为c数组中不同元素值的个数。现在给定b[1~n][]的对应权值数组c[1~n],问是否存在一个排列满足上述要求。

    题意写的可能有点乱,建议读英文题目

    分析:能够发现对于c[i]等于1的位置代表p数组向右循环右移i次后最大的位置落在了右移后数组的第一个位置。那么该位置之后的数都会是最大值,那么在这种情况下再进行循环右移一次有可能使得这个数组的权值+1,但是绝对不可能+2及以上,因为只增加一个不同的值,不可能通过改变一个元素却导致权值增加的值不止1,这个简单分析就能得到.但是权值有可能减少,减少的值可以为任意情况。这就是我们判断序列是否合法的方法。最后需要注意的一点就是数组中不可能出现两个1,因为最大值只会有一个

    1. #include<iostream>
    2. #include<algorithm>
    3. #include<cstring>
    4. #include<cstdio>
    5. #include<cmath>
    6. #include<vector>
    7. #include<queue>
    8. using namespace std;
    9. const int N=2e5+10;
    10. int a[N];
    11. int main()
    12. {
    13. int T;
    14. cin>>T;
    15. while(T--)
    16. {
    17. int n;
    18. scanf("%d",&n);
    19. bool flag=true;
    20. int id=0;
    21. for(int i=1;i<=n;i++)
    22. {
    23. scanf("%d",&a[i]);
    24. a[i+n]=a[i];
    25. if(a[i]==1)
    26. {
    27. if(id) flag=false;
    28. id=i;
    29. }
    30. }
    31. for(int i=id+1;i<id+n;i++)
    32. if(a[i]-a[i-1]>1)
    33. {
    34. flag=false;
    35. break;
    36. }
    37. if(flag) puts("YES");
    38. else puts("NO");
    39. }
    40. return 0;
    41. }

    D1. 388535 (Easy Version)

    题目链接:Problem - D1 - Codeforces

    样例输入: 

    1. 3
    2. 0 3
    3. 3 2 1 0
    4. 0 3
    5. 4 7 6 5
    6. 0 2
    7. 1 2 3

    样例输出:

    1. 0
    2. 4
    3. 3

    题意:给定一个区间[l,r],然后将这个区间的值修改为l~r的一个排列,现在将这个区间内的每一个值都异或上x得到另一个数组,现在给定这个数组问x的值可能是多少,输出任意一个满足题意的x即可。

    注意:简单版本中l=0

    分析:我们可以从l=0这个条件入手,由l=0我们可以知道,[0,r]中所有数中对于二进制的每一位上都有0的个数大于等于1的个数,所以我们对于修改后的数组统计每一位上1的个数,如果出现了1的个数大于0的个数,说明x的这一位为1,导致0和1进行了反转,否则就是0,代表未反转,通过这个方法我们就可以求出x的值。

    1. #include<iostream>
    2. #include<algorithm>
    3. #include<cstring>
    4. #include<cstdio>
    5. #include<cmath>
    6. #include<vector>
    7. #include<queue>
    8. using namespace std;
    9. const int N=2e5+10;
    10. int a[N];
    11. int main()
    12. {
    13. int T;
    14. cin>>T;
    15. while(T--)
    16. {
    17. int l,r;
    18. scanf("%d%d",&l,&r);
    19. for(int i=l;i<=r;i++)
    20. scanf("%d",&a[i]);
    21. long long x=0;
    22. for(int i=0;i<17;i++)
    23. {
    24. int t0=0,t1=0;
    25. for(int j=l;j<=r;j++)
    26. if(a[j]>>i&1) t1++;
    27. else t0++;
    28. if(t1>t0) x+=1<<i;
    29. }
    30. printf("%lld\n",x);
    31. }
    32. return 0;
    33. }

    D2. 388535 (Hard Version)

    题目链接:Problem - D2 - Codeforces

    样例输入: 

    1. 3
    2. 4 7
    3. 3 2 1 0
    4. 4 7
    5. 4 7 6 5
    6. 1 3
    7. 0 2 1

    样例输出:

    1. 4
    2. 0
    3. 3

    题意:给定一个区间[l,r],然后将这个区间的值修改为l~r的一个排列,现在将这个区间内的每一个值都异或上x得到另一个数组,现在给定这个数组问x的值可能是多少,输出任意一个满足题意的x即可。

    注意:困难版本中l不一定为0

    分析:我一开始还是按照通过分析1的个数是否发生变化来分析该位是否发生0和1的反转,但是交上之后发现wa了,通过分析发现对于0的数目和1的数目相同的情况时利用这种分析方法会出现问题,比如[1,2]^2=[0,3],我们能够发现这样就会出现问题。

    下面来阐述一下正解:

    我们知道对于所给的数组b[]是由原数组a[]^x得到的,那么就有a[]=b[]^x,所以x一定是对于任意的i满足l<=i<=r,a[i]^b[j],因为只有这样我们才能通过a[i]^b[j]^b[j]得到a[i],我们可以选择a[i]=l,那么就是l^b[j]中的一个(l<=j<=r),我们暴力判断一下即可。我们知道由于b[j]!=b[k](j!=k),那么就有l^b[j]!=l^b[k],也就是说l异或上r-l+1个不同的b数组会得到r-l+1个不同的数,我们要保证这r-l+1个数是l~r的一个排列,等价于判断这r-l+1个数中的最大值是r,最小值是l,这个复杂度是log级别的,再加上对n个数进行判断,所以复杂度总体是nlogn的,求异或最大值最小值就是tire树的模板题,直接利用tire树优化一下就可以了

    1. #include<iostream>
    2. #include<algorithm>
    3. #include<cstring>
    4. #include<cstdio>
    5. #include<cmath>
    6. #include<vector>
    7. #include<queue>
    8. using namespace std;
    9. const int N=2e6+10;
    10. int a[N];
    11. int son[N][2],idx;
    12. void insert(int x)
    13. {
    14. int p=0;
    15. for(int i=16;i>=0;i--)
    16. {
    17. int u=x>>i&1;
    18. if(!son[p][u]) son[p][u]=++idx;
    19. p=son[p][u];
    20. }
    21. }
    22. int max_val(int x)
    23. {
    24. int ans=0;
    25. int p=0;
    26. for(int i=16;i>=0;i--)
    27. {
    28. int u=x>>i&1;
    29. if(son[p][!u])
    30. {
    31. ans+=1<<i;
    32. p=son[p][!u];
    33. }
    34. else
    35. p=son[p][u];
    36. }
    37. return ans;
    38. }
    39. int min_val(int x)
    40. {
    41. int ans=0;
    42. int p=0;
    43. for(int i=16;i>=0;i--)
    44. {
    45. int u=x>>i&1;
    46. if(son[p][u])
    47. p=son[p][u];
    48. else
    49. {
    50. p=son[p][!u];
    51. ans+=1<<i;
    52. }
    53. }
    54. return ans;
    55. }
    56. int main()
    57. {
    58. int T;
    59. cin>>T;
    60. while(T--)
    61. {
    62. idx=0;
    63. int l,r;
    64. scanf("%d%d",&l,&r);
    65. for(int i=l;i<=r;i++)
    66. {
    67. scanf("%d",&a[i]);
    68. insert(a[i]);
    69. }
    70. for(int i=l;i<=r;i++)
    71. {
    72. if(max_val(a[i]^l)==r&&min_val(a[i]^l)==l)
    73. {
    74. printf("%d\n",a[i]^l);
    75. break;
    76. }
    77. }
    78. for(int i=0;i<=idx;i++)
    79. son[i][0]=son[i][1]=0;
    80. }
    81. return 0;
    82. }

  • 相关阅读:
    互联网那些技术 | 高可用三大利器 — 熔断、限流和降级
    tensor的不同维度种类
    【408考研】数据结构 —— 第二章 线性表
    Linux文件目录结构详解:根目录和常见子目录介绍
    数字孪生技术在光网络中的应用与问题
    Flink的简单学习(kafka)三
    redis的数据类型及操作
    android基础学习
    leetcode每天5题-Day50
    C. Best Binary String
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/127413736