当前位置:   article > 正文

Codeforces Round #788 (Div. 2)题解_codeforces round 788 (div. 2) f

codeforces round 788 (div. 2) f

A-

题目大意:给定一个序列,能够交换任意两个数的正负性,问能否构造出不递减

方法: 负数必须是连续出现在前段,正数连续出现在后段。即构造出的序列是先负数后正数。

代码:

  1. #include<iostream>
  2. using namespace std;
  3. const int N=100010;
  4. int p[N];
  5. int main()
  6. {
  7. cin.tie(0);
  8. cout.tie(0);
  9. ios::sync_with_stdio(0);
  10. int t;cin>>t;
  11. while(t--)
  12. {
  13. int n;
  14. cin>>n;
  15. int cntn=0;
  16. for(int i=1;i<=n;i++)
  17. {
  18. int x;
  19. cin>>x;
  20. p[i]=abs(x);
  21. if(x<0)cntn++;
  22. }
  23. bool flag=true;
  24. for(int i=1;i<=n;i++)
  25. {
  26. if(cntn)
  27. {
  28. cntn--;
  29. p[i]=-p[i];
  30. }
  31. if(i-1)
  32. {
  33. if(p[i-1]>p[i])
  34. {
  35. flag=false;
  36. break;
  37. }
  38. }
  39. }
  40. if(flag)
  41. {
  42. cout<<"YES"<<endl;
  43. }else
  44. {
  45. cout<<"NO"<<endl;
  46. }
  47. }
  48. return 0;
  49. }

B-

题目大意:给定一个小写字母序列,再给若干个特殊的字母,每次操作,可以将序列中特殊字母的前一个字母删除。问删到不能删的时候,操作了几次

方法:   对于序列中出现的第一个特殊字母,它的操作数是前面的字母数; 

对于前有特殊字母的特殊字母,它的操作数是(1+特殊字母之间的字母数)

这个1是当删到特殊字母连续的时候,删一次就可以使开端只剩一个特殊字母。

然后将所有操作数取最大值

代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<vector>
  4. using namespace std;
  5. const int N=200010;
  6. char a[N];
  7. bool st[26];
  8. int main()
  9. {
  10. int t;
  11. cin>>t;
  12. while(t--)
  13. {
  14. memset(st,false,sizeof st);
  15. vector<int> ans;
  16. int n;
  17. cin>>n;
  18. cin>>a+1;
  19. int k;cin>>k;
  20. for(int i=1;i<=k;i++)
  21. {
  22. char c;cin>>c;
  23. st[c-'a']=true;
  24. }
  25. int cnt1=0;
  26. int cnt2=0;
  27. for(int i=1;i<=n;i++)
  28. {
  29. if(st[a[i]-'a'])
  30. {
  31. ans.push_back(cnt1+cnt2);
  32. cnt2=1;
  33. cnt1=0;
  34. }else
  35. {
  36. cnt1++;
  37. }
  38. }
  39. int res=0;
  40. for(auto x:ans)
  41. {
  42. res=max(res,x);
  43. }
  44. cout<<res<<endl;
  45. }
  46. return 0;
  47. }

C-

题目大意:给定2个全排列a,b。 再给一个需要构造的全排列c。

c[i]不是0:c[i]要么为a[i]要么为b[i],

c[i]是0,那么就可以任取a[i]或b[i]。

现在问能构造符合条件的全排列c的数字。

方法:   对于确定值的c[i],不用考虑。不确定的就话,如果可以使对应所有的a[i],b[i]成一个圈,那么就有两种情况,即答案乘2。

注意:如果对于任选的a[i],b[i](c!=0)在确定的a[i],b[i](c==0)出现过,说明不能任选,那么就构不成一个圈。

代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<map>
  4. using namespace std;
  5. const int N=100010;
  6. const int mod=1e9+7;
  7. typedef pair<int,int> PII;
  8. int a[N],b[N];
  9. int p[N];
  10. bool st[N];
  11. bool v[N];
  12. int main()
  13. {
  14. cin.tie(0);
  15. cout.tie(0);
  16. ios::sync_with_stdio(0);
  17. int t;cin>>t;
  18. while(t--)
  19. {
  20. memset(v,false,sizeof v);
  21. memset(st,false,sizeof st);
  22. int n;
  23. cin>>n;
  24. for(int i=1;i<=n;i++)
  25. {
  26. cin>>a[i];
  27. }
  28. for(int i=1;i<=n;i++)
  29. {
  30. cin>>b[i];
  31. }
  32. for(int i=1;i<=n;i++)
  33. {
  34. int c;
  35. cin>>c;
  36. if(c)
  37. {
  38. st[a[i]]=true;
  39. st[b[i]]=true;
  40. }
  41. }
  42. for(int i=1;i<=n;i++)
  43. {
  44. p[a[i]]=b[i];
  45. }
  46. long long res=1;
  47. for(int i=1;i<=n;i++)
  48. {
  49. if(!v[i])
  50. {
  51. int j=i;
  52. int cnt=0;
  53. bool flag=false;
  54. while(!v[j])
  55. {
  56. v[j]=true;
  57. flag|=st[j];
  58. j=p[j];
  59. cnt++;
  60. }
  61. if(cnt!=1&&!flag)
  62. {
  63. res*=2;
  64. res%=mod;
  65. }
  66. }
  67. }
  68. cout<<res<<endl;
  69. }
  70. return 0;
  71. }

D-

题目大意:给定一个无限大的六边形网格区域(蜂窝吗),每次可以画一条直线。

直线有三种情况:与x轴平行,夹60°,夹120°

这些直线相互之间和网格之间可以形成等边三角形。

现给定得到的三角形数量,问最少画了多少根直线

方法:   规律:每次加一根直线,最多可以增加另外两种直线数量和的二倍。

预处理出直线数所能构造出的最多三角形数。

然后二分。

代码:

代码1:找到规律后发现每一轮(加三根不同直线)会多产生12个三角形。

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. long long res=0;
  6. long long temp=0;
  7. for(int i=0;res<=1e9;i++)
  8. {
  9. cout<<i<<" "<<3*i<<" "<<res<<endl;
  10. temp+=12;
  11. res+=temp;
  12. }
  13. //12909 38727 999853686
  14. return 0;
  15. }

代码2:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. using namespace std;
  5. const int N=40000;
  6. int res[N];
  7. int main()
  8. {
  9. int t;cin>>t;
  10. res[1]=0;res[2]=2;res[3]=6;
  11. int cnt[3]={1,1,1};
  12. for(int i=4;i<=38730;i++)
  13. {
  14. int j=i%3;
  15. int temp=0;
  16. for(int k=0;k<3;k++)
  17. {
  18. if(k!=j)
  19. {
  20. temp+=cnt[k]*2;
  21. }
  22. }
  23. cnt[j]++;
  24. res[i]=res[i-1]+temp;
  25. }
  26. while(t--)
  27. {
  28. int n;cin>>n;
  29. int l=1,r=38730;
  30. while(l<r)
  31. {
  32. int mid=l+r>>1;
  33. if(res[mid]>=n)
  34. {
  35. r=mid;
  36. }else
  37. {
  38. l=mid+1;
  39. }
  40. }
  41. cout<<r<<endl;
  42. }
  43. return 0;
  44. }

E-

题目大意:一颗有n个点的树,边和点都有权值,是[1,2n-1]的全排列,找到一个根节点,使从根节点开始最大路径值最小。

方法:   参考于https://zhuanlan.zhihu.com/p/510465004

讲的挺好的,是大佬%%%%

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/519112?site
推荐阅读
相关标签
  

闽ICP备14008679号