[关闭]
@wwwqeqeqeqe 2019-04-26T10:18:39.000000Z 字数 4908 阅读 653

Codeforces Round #553 (div.2)

codeforces

A Maxim and Biology

题目大意:

给你一个字符串,让你进行最少次数的改变,使得能在这个字符串中找到连续的ACTG。(Z变为A和A变为Z都算变换一次)

解题思路:

暴力搜索所有的字符,每次计算他及后面连续的四个字符变为ACTG所需要的最少次数,取最小即可。

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int INF=0x3f3f3f3f;
  4. const int maxn=1e2+5;
  5. const char a[]={"ACTG"};
  6. int n;
  7. char s[maxn];
  8. int main()
  9. {
  10. cin >> n;
  11. cin >> s;
  12. int ans=INF;
  13. for(int i=0;i<n-3;i++)
  14. {
  15. int sum=0;
  16. for(int j=i;j<i+4;j++)
  17. {
  18. if(s[j]>=a[j-i])
  19. {
  20. sum+=min(s[j]-a[j-i],'Z'-s[j]+a[j-i]-'A'+1);
  21. }
  22. else
  23. {
  24. sum+=min(a[j-i]-s[j],s[j]-'A'+'Z'-a[j-i]+1);
  25. }
  26. }
  27. ans=min(ans,sum);
  28. }
  29. cout << ans << endl;
  30. return 0;
  31. }

B Dima and a Bad XOR

题目大意:

给你一个由非负整数组成的n*m的矩阵,让你从矩阵的每一行中选取一个数出来,使这些选出来的数按位异或严格大于零。

解题思路:

先把每一行的第一个元素进行按位异或。再从第一行开始,查找是否存在一个数x,使这个数和这一行的第一个数不同。如果不存在这个数并且每一行第一个元素异或得到的结果为0,那么这个矩阵就不存在满足条件的取法。如果第一个元素按位异或结果不为0,则每行都去第一个元素,如果为0,就把之前找到的x用来替换x那一行的第一个数进行异或。

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=500+5;
  4. int n,m;
  5. int mp[maxn][maxn];
  6. int x,y,ans;
  7. int main()
  8. {
  9. cin >> n >> m;
  10. x=-1,y=-1,ans=0;
  11. for(int i=0; i<n; i++)
  12. {
  13. for(int j=0; j<m; j++)
  14. {
  15. cin >> mp[i][j];
  16. if(x == -1 && j!=0 && mp[i][j]!=mp[i][0])
  17. {
  18. x=i;
  19. y=j;
  20. }
  21. }
  22. ans^=mp[i][0];
  23. }
  24. if(ans == 0 && x == -1)
  25. {
  26. cout << "NIE" << endl;
  27. }
  28. else
  29. {
  30. cout << "TAK" << endl;
  31. if(ans != 0)
  32. {
  33. for(int i=0; i<n-1; i++)
  34. cout << 1 << " ";
  35. cout << 1 <<endl;
  36. }
  37. else
  38. {
  39. if(x!=n-1)
  40. {
  41. for(int i=0; i<n-1; i++)
  42. {
  43. if(x == i)
  44. cout << y+1 << " ";
  45. else
  46. cout << 1 << " ";
  47. }
  48. cout << 1 << endl;
  49. }
  50. else
  51. {
  52. for(int i=0;i<n-1;i++)
  53. cout << 1 << " ";
  54. cout << y+1 << endl;
  55. }
  56. }
  57. }
  58. return 0;
  59. }

C Problem for Nazar

题目大意:

将数字分为偶数和奇数两种,数字的排列顺序不同于普通的排列方式,而是先取一个奇数,然后取两个偶数,再取四个奇数······以此类推。给你两个数l和r,计算出第l位到第r位所有数字的和。(1到10的排列顺序为1,2,4,3,5,7,9,6,8,10)

解题思路:

我们计算出前l-1和数的和以及前r个数的和,将他们两个相减便能够得到我们要的最终答案。在计算前k个数的和时,按照题目要求的排列方式,从第一个数1开始一直按照规则暴力计算我们一共选取了多少个奇数和多少个偶数,再通过等差数列求和公式,计算出前k个数的和。

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const long long mod=1e9+7;
  4. long long l,r;
  5. long long cal(long long n)
  6. {
  7. long long odd=0,even=0;
  8. long long cnt=0,mark=0;
  9. for(long long i=1;cnt<n;i*=2)
  10. {
  11. long long t=min(n-cnt,i);
  12. cnt+=t;
  13. if(mark == 0)
  14. odd+=t;
  15. else
  16. even+=t;
  17. mark ^=1 ;
  18. }
  19. odd%=mod;
  20. even%=mod;
  21. long long ans=(odd*odd)%mod+(even*even)%mod+even%mod;
  22. return ans%mod;
  23. }
  24. int main()
  25. {
  26. long long k=1;
  27. cin >> l >> r;
  28. cout << ((cal(r)-cal(l-1))%mod+mod)%mod << endl;
  29. return 0;
  30. }

D Stas and the Queue at the Buffet

题目大意:

有N个人横向排队,每个人有两个值ai和bi,每个人有一个权值,这个权值是他左边的人的个数乘以ai和右边的人乘以bi的和。求所有人的这个权值的和的最小值。

解题思路:

将所有人按照ai-bi从小到大进行排序,越小的安排在越右边,最后求和。(不懂为啥这个题能放到D去)

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=1e5+5;
  4. int n;
  5. struct node
  6. {
  7. long long l,r;
  8. };
  9. node a[maxn];
  10. bool cmp(node x,node y)
  11. {
  12. return (x.r-x.l)<(y.r-y.l);
  13. }
  14. int main()
  15. {
  16. cin >> n;
  17. for(int i=0;i<n;i++)
  18. {
  19. cin >> a[i].l >> a[i].r;
  20. }
  21. sort(a,a+n,cmp);
  22. long long ans=0;
  23. for(int i=0;i<n;i++)
  24. {
  25. ans+=i*a[i].l+(n-i-1)*a[i].r;
  26. }
  27. cout << ans << endl;
  28. return 0;
  29. }

E Number of Components

题目大意:

给你n个数,然后定义一个公式f(i,j)=k表示将i到j看成一个连通块时从i到j这些数字的连通块个数为k。求从f(1,1)到f(n,n)的和。

解题思路:

我们首先枚举每一个节点都是当前连通块的左节点。那么,当a[i-1]<a[i]时,a[i]作为该连通块的左起点可以取[a[i-1]+1,a[i]],区间右边取值可以取[a[i],n],总计有取法(a[i]-a[i-1])*(n-a[i]+1)种。当a[i-1]>a[i]时,区间左取值可以取[a[i],a[i-1]-1],右边可以取值[1,a[i]],总数为(a[i-1]-a[i])*a[i]。当a[i]=a[i-1]时,a[i]不可能作为左端点被取到。最后将每个点的权值相加。

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=1e5+5;
  4. long long n;
  5. long long a[maxn];
  6. int main()
  7. {
  8. cin >> n;
  9. for(int i=1;i<=n;i++)
  10. {
  11. cin >> a[i];
  12. }
  13. a[0]=a[n+1]=n+1;
  14. long long ans=0;
  15. for(int i=1;i<=n;i++)
  16. {
  17. if(a[i-1]<a[i])
  18. ans+=(a[i]-a[i-1])*(n-a[i]+1);
  19. else if(a[i-1]>a[i])
  20. ans+=a[i]*(a[i-1]-a[i]);
  21. }
  22. cout << ans << endl;
  23. return 0;
  24. }

F Sonya and Informatics

题目大意:

给出n个只有0或1的数,以及一个数字k。接下来进行k次操作,每次操作交换这n个数中的两个数。询问在k次操作之后,这n个数为不下降序列的概率是多少?

解题思路:

很明显,因为这n个数只有0和1,那么,不下降序列只有可能为前面的数全为0,后面的数全为1。假设0个个数为a,1的个数为b,d[i][j]表示完成i次操作后,前a个数字中有j个0的操作数量。设最原始的数组中,前a个数字里有c个0.我们将d[0][c]初始化为1,那么,问题的答案就为d[k][a]/(d[k][0]+d[k][1]+d[k][2]+······+d[k][a])。
考虑转移方程,d[i][j]可以从d[i-1][j-1],d[i-1][j]和d[i-1][j+1]转移而来。其中d[i-1][j]表示这次转移为0换0或者1换1或者交换的两个数的序号都不在前a个数内或douzai。d[i-1][j-1]表示前a个数中的1和后b个数中的0交换。d[i-1][j+1]表示前a个数中的0和后b个数中的1交换。所以得到转移方程为:
d[i][j]=d[i-1][j]*(C(a,2)+C(b,2)+j*(a-j)+(a-j)*(b-a+j))+d[i-1][j-1]*(a-j+1)*(a-j+1)+d[i-1][j+1]*(j+1)*(b-a+j+1)。
因为d[i][*]只和d[i-1][*]有关,所以我们可以使用矩阵快速幂来求d[i][*]。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const ll mod = 1e9 + 7;
  5. struct SquareMatrix
  6. {
  7. SquareMatrix(int _n) : n(_n)
  8. {
  9. data.assign(_n, vector<ll>(_n, 0));
  10. }
  11. vector<ll> &operator[](int i)
  12. {
  13. return data[i];
  14. }
  15. const vector<ll> &operator[](int i) const
  16. {
  17. return data[i];
  18. }
  19. SquareMatrix operator*(const SquareMatrix &other) const
  20. {
  21. assert(n == other.n);
  22. SquareMatrix ret(n);
  23. for (int i = 0; i < n; ++i)
  24. {
  25. for (int j = 0; j < n; ++j)
  26. {
  27. for (int k = 0; k < n; ++k)
  28. {
  29. ret[i][j] = (ret[i][j] + data[i][k] * other[k][j]) % mod;
  30. }
  31. }
  32. }
  33. return ret;
  34. }
  35. vector<vector<ll>> data;
  36. int n;
  37. };
  38. SquareMatrix quickpower(SquareMatrix m, int p)
  39. {
  40. int n = m.n;
  41. SquareMatrix ret(n);
  42. for (int i = 0; i < n; ++i) ret[i][i] = 1;
  43. while (p)
  44. {
  45. if (p & 1)
  46. {
  47. ret = ret * m;
  48. }
  49. m = m * m;
  50. p >>= 1;
  51. }
  52. return ret;
  53. }
  54. ll quickpower(ll x, int p)
  55. {
  56. ll ret = 1;
  57. while (p)
  58. {
  59. if (p & 1) ret = (ret * x) % mod;
  60. x = (x * x) % mod;
  61. p >>= 1;
  62. }
  63. return ret;
  64. }
  65. int main()
  66. {
  67. int n, k;
  68. cin >> n >> k;
  69. vector<int> a(n);
  70. int x = 0, y = 0, z = 0;
  71. for (int i = 0; i < n; ++i)
  72. {
  73. cin >> a[i];
  74. x += a[i] == 0;
  75. }
  76. y = n - x;
  77. for (int i = 0; i < x; ++i)
  78. z += a[i] == 0;
  79. SquareMatrix m(x + 1);
  80. for (int i = 0; i <= x; ++i)
  81. {
  82. m[i][i] = x * (x - 1) / 2 + y * (y - 1) / 2 + i * (x - i) + (x - i) * (y - x + i);
  83. if (i - 1 >= 0) m[i][i - 1] = (x - i + 1) * (x - i + 1);
  84. if (i + 1 <= x) m[i][i + 1] = (i + 1) * (y - x + i + 1);
  85. }
  86. m = quickpower(m, k);
  87. ll ans = 0;
  88. for (int i = 0; i <= x; ++i)
  89. ans = (ans + m[i][z]) % mod;
  90. ans = m[x][z] * quickpower(ans, mod - 2) % mod;
  91. cout << ans << endl;
  92. return 0;
  93. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注