Codeforce Round #547 div3

痛定思痛。 2022-01-21 01:57 322阅读 0赞

A.Game 23

1.题目

A

2.思路

直接考虑dfs即可,记录最小值,最后输出即可

  1. #include <stdio.h>
  2. const int maxn=1e9+7;
  3. int n,m;
  4. int min=maxn;
  5. void dfs(int n,int tar,int step)
  6. {
  7. if(n>tar)
  8. {
  9. return;
  10. }
  11. if(n==tar)
  12. {
  13. min=min<step?min:step;
  14. }
  15. dfs(n*2,tar,step+1);
  16. dfs(n*3,tar,step+1);
  17. }
  18. int main()
  19. {
  20. scanf("%d%d",&n,&m);
  21. if(n==m)
  22. {
  23. printf("0\n");
  24. }
  25. else
  26. {
  27. dfs(n,m,0);
  28. if(min!=maxn)
  29. printf("%d\n",min);
  30. else
  31. printf("-1\n");
  32. }
  33. return 0;
  34. }#include <stdio.h>
  35. const int maxn=1e9+7;
  36. int n,m;
  37. int min=maxn;
  38. void dfs(int n,int tar,int step)
  39. {
  40. if(n>tar)
  41. {
  42. return;
  43. }
  44. if(n==tar)
  45. {
  46. min=min<step?min:step;
  47. }
  48. dfs(n*2,tar,step+1);
  49. dfs(n*3,tar,step+1);
  50. }
  51. int main()
  52. {
  53. scanf("%d%d",&n,&m);
  54. if(n==m)
  55. {
  56. printf("0\n");
  57. }
  58. else
  59. {
  60. dfs(n,m,0);
  61. if(min!=maxn)
  62. printf("%d\n",min);
  63. else
  64. printf("-1\n");
  65. }
  66. return 0;
  67. }

B.Maximal Continuous Rest

1.题目

B

2.解答

问题看起来有点像循环数组,求最大连续字段的最大长度,只要加一个%n循环求最大长度即可。

  1. #include <stdio.h>
  2. const int maxn=2*1e5+7;
  3. int n;
  4. int time[maxn];
  5. int max=-1;
  6. int main()
  7. {
  8. scanf("%d",&n);
  9. for(int i=0;i<n;i++)
  10. {
  11. scanf("%d",&time[i]);
  12. }
  13. int count=1;
  14. int i;
  15. for(i=0;i<n;i++)
  16. {
  17. if(time[i])
  18. break;
  19. }
  20. if(i==n)
  21. {
  22. printf("0\n");
  23. return 0;
  24. }
  25. for(i=0;i<2*n;i++)
  26. {
  27. if(time[i%n]&&time[(i+1)%n])
  28. {
  29. count++;
  30. }
  31. else
  32. {
  33. max=max>count?max:count;
  34. count=1;
  35. }
  36. }
  37. max=max>count?max:count;
  38. printf("%d\n",max);
  39. return 0;
  40. }

C.Polycarp Restores Permutation

1.题目

C

2.解答

我们这样考虑,假设原来的序列为a,b,c,d…h.

现在我们有b-a,c-b,d-c…,那么现在我们将两两之间的差相加起来

会得到b-a,c-a,d-a,e-a,f-a…我们假设其中任意一个元素xi为1,那么我们可以知道,在xi的位置此时的和是最小的,由此我们可以找到1的位置。任何一个属于[1,n]的元素-a,不会比1-a更小(十分显然),找到一的位置,剩下的东西就十分好判断了

  1. #include <stdio.h>
  2. #include <algorithm>
  3. #include <string.h>
  4. using namespace std;
  5. int n;
  6. const int maxn=2*1e5+7;
  7. long long int q[maxn];
  8. long long int sum[maxn];
  9. int main()
  10. {
  11. scanf("%d",&n);
  12. long long int low=99999999;
  13. memset(sum,0,sizeof(sum));
  14. int b[maxn]={0};
  15. for(int i=1;i<=n-1;i++)
  16. {
  17. scanf("%lld",&q[i]);
  18. sum[i]=sum[i-1]+q[i];
  19. }
  20. for(int i=0;i<=n-1;i++)
  21. {
  22. low=min(low,sum[i]);//寻找一
  23. }
  24. for(int i=0;i<n;i++)
  25. {
  26. if(sum[i]-low+1>n||b[sum[i]-low]>=1)
  27. {
  28. //不满足情况的点有数值大于n
  29. //或者中间出现0
  30. printf("-1\n");
  31. return 0;
  32. }
  33. b[sum[i]-low]=1;
  34. }
  35. for(int i=0;i<n;i++)
  36. {
  37. printf("%lld ",sum[i]-low+1);
  38. }
  39. puts("");
  40. return 0;
  41. }

D.Colored Boots

1.题目

D

2.解答

首先我们先对两个字符数组进行排序,将’?’放在数组的最后边

然后我们分别从两个字符数组的开头开始比较,此处相当于寻找字串。寻找字串完毕后,剩下的元素就是互相不匹配的和’?’,那么之后我们从第一个数组的末尾开始,将‘?’与第二个数组从头开始剩下的元素进行匹配,再对第二个数组进行同样的操作,即可

  1. #include <stdio.h>
  2. #include <algorithm>
  3. #include <vector>
  4. #include <stack>
  5. using namespace std;
  6. const int maxn=15*1e4+7;
  7. vector<pair<int,int> >ans;
  8. struct node
  9. {
  10. char c;
  11. int num;
  12. };
  13. node d1[maxn];
  14. node d2[maxn];
  15. node s1[maxn];
  16. node s2[maxn];
  17. bool cmp(node a,node b)
  18. {
  19. if(a.c=='?')
  20. {
  21. return false;
  22. }
  23. if(b.c=='?')
  24. {
  25. return true;
  26. }
  27. return a.c<b.c;
  28. }//sort
  29. void read(int n,node *a)
  30. {
  31. char c;
  32. for(int i=1;i<=n;i++)
  33. {
  34. c=getchar();
  35. a[i].c=c;
  36. a[i].num=i;
  37. }
  38. return;
  39. }
  40. int main()
  41. {
  42. int n;
  43. scanf("%d",&n);
  44. getchar();
  45. char c;
  46. ans=vector<pair<int,int> >(n);
  47. read(n,d1);
  48. getchar();
  49. read(n,d2);
  50. sort(d1+1,d1+1+n,cmp);
  51. sort(d2+1,d2+1+n,cmp);
  52. int c1=0;
  53. int c2=0;
  54. int i=1;
  55. int j=1;
  56. ans.clear();
  57. while(1)
  58. {
  59. if(i>n||j>n)
  60. {
  61. break;
  62. }
  63. if(d1[i].c==d2[j].c)
  64. {
  65. ans.push_back(make_pair(d1[i].num,d2[j].num));
  66. i++;
  67. j++;
  68. }
  69. else if(d1[i].c>d2[j].c)
  70. {
  71. s2[c2]=d2[j];//存入d2没有匹配的元素
  72. c2++;
  73. j++;
  74. }
  75. else if(d1[i].c<d2[j].c)
  76. {
  77. s1[c1]=d1[i];//存入d1没有匹配的元素
  78. c1++;
  79. i++;
  80. }
  81. }
  82. for(i;i<=n;i++)
  83. {
  84. s1[c1]=d1[i];//放入剩下的元素
  85. c1++;
  86. }
  87. for(j;j<=n;j++)
  88. {
  89. s2[c2]=d2[j];
  90. c2++;
  91. }
  92. int c_2=0;//从d2的头开始匹配
  93. for(i=c1-1;i>=0;i--)
  94. {
  95. if(s1[i].c=='?')
  96. {
  97. ans.push_back(make_pair(s1[i].num,s2[c_2].num));
  98. c_2++;
  99. }
  100. else
  101. {
  102. break;
  103. }
  104. }
  105. int c_1=0;//从d1的头开始匹配
  106. for(j=c2-1;j>=c_2;j--)
  107. {
  108. if(s2[j].c=='?')
  109. {
  110. ans.push_back(make_pair(s1[c_1].num,s2[j].num));
  111. c_1++;
  112. }
  113. else
  114. {
  115. break;
  116. }
  117. }
  118. printf("%d\n",ans.size());
  119. if(ans.size())
  120. for(auto it:ans)
  121. {
  122. printf("%d %d\n",it.first,it.second);
  123. }
  124. return 0;
  125. }

E.Superhero Battle

1.题目

E

2.解答

首先我们先判断一个回合,一个回合的特殊情况是

1.回合时间尚未结束,直接就打死了

2.一个回合所造成的伤害,为0或者小于0,那么此时就是没有办法打死的情况

接着,我们要求出一个回合能够造成的伤害D,以及一个回合内所能造成伤害的最大值dmax,我们用总的血量H/D,可得到一个大致的回合数R,但是由于可能dmax要大于D,所以可能在R回合之前,H就已经小于等于0了,我们应当调整R为R-dmax/D,这样可以解决上面问题,然后在这个回合的基础上,累计每分钟的伤害值,直到H小于或者等于0即可

  1. #include <stdio.h>
  2. #include <algorithm>
  3. #include <math.h>
  4. using namespace std;
  5. const int maxn=4*1e5+7;
  6. int damage[maxn];
  7. long long int sum[maxn]={0};
  8. long long int low=maxn;
  9. int main()
  10. {
  11. long long int H;
  12. long long int n;
  13. scanf("%lld%lld",&H,&n);
  14. long long int sum=0;
  15. for(long long int i=0;i<n;i++)
  16. {
  17. scanf("%d",&damage[i]);
  18. sum+=damage[i];
  19. low=min(low,sum);
  20. }
  21. long long int oH=H;
  22. for(long long int i=0;i<n;i++)
  23. {
  24. H+=damage[i];
  25. if(H<=0)
  26. {
  27. printf("%d\n",i+1);
  28. return 0;
  29. }
  30. }//判断第一个回合
  31. long long int round=1;
  32. long long int minute=0;
  33. if(H>=oH)
  34. {
  35. printf("-1");
  36. }
  37. else
  38. {
  39. H=oH;
  40. round=H/abs(sum);
  41. long long int base=abs(low/sum);
  42. H+=(round-base)*sum;
  43. round-=base;
  44. long long int result=round*n;
  45. for(int i=0;;i++)
  46. {
  47. H+=damage[i%n];
  48. result++;
  49. if(H<=0)
  50. {
  51. printf("%lld",result);
  52. break;
  53. }
  54. }
  55. }
  56. return 0;
  57. }

F.Same Sum Blocks

1.题目

F

2.解答

由于F1和F2的题目几乎是一样的,所以我们放在一起来讲了。

首先我们记录下,从数组开头开始,所有和的可能的情况。并对其按照值的大小进行排列,如果值相同则会按照,右边节点从小到大排列,这里应用了贪心的思想,如果保证右边节点最小,那么右边的序列会更长一点,相同的可能也会更大一点。然后剩下的问题就相当于是,数组,求最大连续相同值的长度。

  1. #include <stdio.h>
  2. #include <algorithm>
  3. #include <vector>
  4. #include <map>
  5. using namespace std;
  6. const int maxn=1507;
  7. vector<pair<int,int> >ans;
  8. vector<pair<int,int> >ans1;
  9. struct node
  10. {
  11. int num;
  12. int left;
  13. int right;
  14. };
  15. node test[maxn];
  16. node sum[1000*maxn];
  17. bool cmp(node a,node b)
  18. {
  19. if(a.num==b.num)
  20. {
  21. return a.right<b.right;
  22. }
  23. return a.num<b.num;
  24. }
  25. int main()
  26. {
  27. int n;
  28. scanf("%d",&n);
  29. for(int i=1;i<=n;i++)
  30. {
  31. scanf("%d",&test[i].num);
  32. test[i].left=i;
  33. test[i].right=i;
  34. }
  35. int count=1;
  36. for(int i=0;i<n;i++)
  37. for(int j=1;j+i<=n;j++)
  38. {
  39. for(int k=i;k>=0;k--)
  40. {
  41. sum[count].num+=test[j+k].num;//求所有的段的和
  42. }
  43. sum[count].left=j;
  44. sum[count].right=j+i;
  45. count++;
  46. }
  47. ans1=vector<pair<int,int> >(n);
  48. ans1.clear();
  49. sort(sum+1,sum+count,cmp);
  50. //for(int i=1;i<count;i++)
  51. //{
  52. //printf("%d %d %d\n",sum[i].num,sum[i].left,sum[i].right);
  53. //}
  54. int high=-1;
  55. for(int i=1;i<count;i++)
  56. {
  57. int tar=sum[i].num;
  58. int r=sum[i].right;
  59. int count=1;
  60. ans1.push_back({sum[i].left,sum[i].right});
  61. for(int j=1;;j++)
  62. {
  63. if(sum[i+j].num==tar)
  64. {
  65. if(sum[i+j].left>r)//必须满足这个条件
  66. {
  67. r=sum[i+j].right;
  68. count++;
  69. ans1.push_back({sum[i+j].left,sum[i+j].right});
  70. }
  71. }
  72. else
  73. {
  74. if(count>high)
  75. {
  76. high=count;
  77. ans=ans1;
  78. }
  79. ans1.clear();
  80. count=1;
  81. i=i+j-1;
  82. break;
  83. }
  84. }
  85. }
  86. printf("%d\n",ans.size());
  87. for(auto it:ans)
  88. {
  89. printf("%d %d\n",it.first,it.second);
  90. }
  91. return 0;
  92. }

G.Privatization of Roads in Treeland

1.题目

G

2.解答

这道题说实话,是真的没搞懂。所以去看了题解。整体来分析题目的意思就是说,在n个城市中最多有k个城市的两条或者两条以上的道路被同一个公司承包。我们将道路被一个公司承包想象为为这条道路染色。根据Dirichlet’s principle。当给图的边染色的时候,如果染色的种类小于最大度数,那么至少有一个点的两条边会染上相同的颜色。这一点还是比较容易证明的。同时我们还可以得到,度数高于颜色的种类的点,都至少会有两条边被染上相同的颜色。(解题的关键所在)。剩下的内容就是dfs的内容。具体见代码注释。(codeforces给的标程)

  1. #include <iostream>
  2. #include <vector>
  3. #include <map>
  4. using namespace std;
  5. int n, k, r;
  6. vector<vector<pair<int,int>>> g;
  7. int D;
  8. vector<int> col;
  9. void dfs(int u, int p, int f) {
  10. //u代表着当前遍历的点,
  11. //p代表着遍历的上一个点,
  12. //f表示进入该点的颜色是什么
  13. int color = 0;
  14. //每一个点的边的颜色从0开始,
  15. //其实从多少开始都一样
  16. for (auto e: g[u])
  17. //遍历与该点向连的所有点
  18. if (p != e.first) {
  19. //去掉回到上一个点的情况
  20. if (color == f) {
  21. color = (color + 1) % D;
  22. //第一次要避免边的颜色与上一条重复
  23. //尽量为从该点出发的边上的颜色多一点
  24. f = -1;
  25. }
  26. col[e.second] = color;
  27. //为边染色
  28. dfs(e.first, u, color);
  29. color = (color + 1) % D;
  30. //下一条边要染不同的颜色
  31. //因为只有D种
  32. //所以要去循环
  33. }
  34. }
  35. int main() {
  36. cin >> n >> k;
  37. g.resize(n);
  38. vector<int> d(n);
  39. for (int i = 0; i + 1 < n; i++) {
  40. int x, y;
  41. cin >> x >> y;
  42. x--, y--;
  43. g[x].push_back({y, i});
  44. //此处为记录与该点相连的所有边的信息;
  45. g[y].push_back({x, i});
  46. d[x]++, d[y]++;
  47. //存储度数
  48. }
  49. map<int,int> cnt;
  50. for (int dd: d)
  51. cnt[dd]++;
  52. //记录度数为dd的点有几个
  53. int kk = n;
  54. D = 0;
  55. for (auto p: cnt)
  56. if (kk > k)
  57. D = p.first,
  58. //p.first为度数
  59. kk -= p.second;
  60. //p.second为个数,
  61. //表示剩下的度数顶点中,
  62. //比现在颜色多的个数,
  63. //要保证这一部分的数量不超过k
  64. else
  65. break;
  66. col = vector<int>(n - 1);
  67. dfs(0, -1, -1);
  68. cout << D << endl;
  69. for (int i = 0; i + 1 < n; i++)
  70. cout << col[i] + 1 << " ";
  71. return 0;
  72. }

发表评论

表情:
评论列表 (有 0 条评论,322人围观)

还没有评论,来说两句吧...

相关阅读