• 2022 年第四届河南省 CCPC 大学生程序设计竞赛vp补题


    Dashboard - 2022 CCPC Henan Provincial Collegiate Programming Contest - Codeforces

    Problem B. Hash

    思路:

    1. 发现31的次幂取模的答案,所以如果一段太长肯定不如拆成2段。
    2. 首先如果一段长度为7,那么无论他的开头是a,eh,n的谁,都有val>=31^6=887503681>P/2
    3. 所以我一定可以把长度大于等于14的拆成2段,使得val(7)+val(7)>P>val(14)
    4. 明确每一段长度才这么一点,我们可以暴力枚举dp,求dp[i],我们每次求出以i结尾的各种长度len(1~13)的val,那么max(dp[i])=max(dp[i-len]+val(len))。因为是环,所以我们需要枚举第一段的可能的13个开头(一段最长为13)
    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define endl "\n"
    5. const int mod=998244353;
    6. const int N=2e5+50;
    7. ll a[N],d[30],dp[N],pre[20];
    8. void mysolve()
    9. {
    10. string s;
    11. cin>>s;
    12. int n=s.size();
    13. for(int i=0; i
    14. {
    15. if(s[i]=='a')a[i]=1;
    16. else if(s[i]=='e')a[i]=2;
    17. else if(s[i]=='h')a[i]=3;
    18. else a[i]=4;
    19. }
    20. ll ans=0;
    21. pre[0]=1;
    22. for(int i=1; i<=13; ++i)pre[i]=pre[i-1]*31%mod;
    23. for(int k=0; k<13; ++k)//枚举开头
    24. {
    25. vectordp(n+15);
    26. int l=k,r=n+l-1;
    27. a[r+1]=a[l];//因为开头移动,所以尾部也移动了
    28. for(int i=l; i<=r; ++i)//遍历dp[i]
    29. {
    30. ll tmp=0;
    31. for(int j=0; j<14&&i-j>=l; ++j)//枚举以i结尾的最优长度获取dp[i]
    32. {
    33. tmp=(tmp+a[i-j]*pre[j])%mod;
    34. if(i-j)dp[i]=max(dp[i],dp[i-j-1]+tmp);
    35. }
    36. }
    37. ans=max(ans,dp[r]);
    38. }
    39. cout<
    40. }
    41. int32_t main()
    42. {
    43. std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    44. mysolve();
    45. return 0;
    46. }

    Problem C. Serval 的试卷答案

    思路:

    1. 对于s[i]>s[i+1]的,显然我们必须把他们隔开。
    2. 而我们需要获取k段,显然需要插k-1个隔板,如果我们把必须隔开的隔开后,剩下可以插空的位置就是可以容易插。所以对于一段[l,r]划分k段,要求必须划分的有cnt段。答案就是组合数\binom{r-l-cnt}{k-1-cnt},显然我们线段树维护好cnt即可
    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define endl "\n"
    5. const int N = 1e5 + 20;
    6. const int mod=998244353;
    7. int a[N];
    8. int n,q;
    9. #define ls p<<1
    10. #define rs p<<1|1
    11. #define mid (t[p].l+((t[p].r-t[p].l)>>1))
    12. ll pre[N],dev[N],tmp[4][4];
    13. struct tree
    14. {
    15. int l,r;
    16. int ld,rd;
    17. int add,cnt;
    18. int sum[4][4];
    19. } t[N<<2];
    20. inline ll fastmi(ll base,ll power)
    21. {
    22. ll ans=1;
    23. while(power)
    24. {
    25. if(power&1)ans=ans*base%mod;
    26. base=base*base%mod;
    27. power>>=1;
    28. }
    29. return ans;
    30. }
    31. inline void pushup(int p)
    32. {
    33. for(int i=0; i<4; ++i)for(int j=0; j<4; ++j)t[p].sum[i][j]=t[ls].sum[i][j]+t[rs].sum[i][j];
    34. t[p].sum[t[ls].rd][t[rs].ld]++;
    35. t[p].ld=t[ls].ld,t[p].rd=t[rs].rd;
    36. t[p].cnt=t[ls].cnt+t[rs].cnt;
    37. if(t[ls].rd>=t[rs].ld)t[p].cnt++;
    38. }
    39. void build(int l,int r,int p)
    40. {
    41. t[p].l=l,t[p].r=r;
    42. if(t[p].l==t[p].r)
    43. {
    44. t[p].ld=t[p].rd=a[l];
    45. return;
    46. }
    47. build(l,mid,ls),build(mid+1,r,rs);
    48. pushup(p);
    49. }
    50. inline void change(int p,int w)
    51. {
    52. for(int i=0; i<4; ++i)for(int j=0; j<4; ++j)tmp[i][j]=t[p].sum[i][j];
    53. for(int i=0; i<4; ++i)for(int j=0; j<4; ++j)t[p].sum[(i+w)%4][(j+w)%4]=tmp[i][j];
    54. t[p].ld=(t[p].ld+w)%4,t[p].rd=(t[p].rd+w)%4;
    55. t[p].cnt=0;
    56. for(int i=0; i<4; ++i)for(int j=i; ~j; --j)t[p].cnt+=t[p].sum[i][j];
    57. t[p].add+=w;
    58. }
    59. inline void lazy(int p)
    60. {
    61. if(t[p].l==t[p].r)t[p].add=0;
    62. if(t[p].add)
    63. {
    64. change(ls,t[p].add),change(rs,t[p].add);
    65. t[p].add=0;
    66. }
    67. }
    68. void update(int l,int r,int p)
    69. {
    70. if(l<=t[p].l&&t[p].r<=r)
    71. {
    72. change(p,1);
    73. return;
    74. }
    75. lazy(p);
    76. if(mid>=l)update(l,r,ls);
    77. if(midupdate(l,r,rs);
    78. pushup(p);
    79. }
    80. int ask(int l,int r,int p)
    81. {
    82. if(l<=t[p].l&&t[p].r<=r)return t[p].cnt;
    83. int ans=0;
    84. lazy(p);
    85. if(mid>=l)ans+=ask(l,r,ls);
    86. if(midask(l,r,rs);
    87. if(l<=mid&&mid=t[rs].ld);
    88. return ans;
    89. }
    90. inline ll C(int n,int m)
    91. {
    92. if(m>n||m<0||n<0)return 0;
    93. return 1ll*pre[n]*dev[m]%mod*dev[n-m]%mod;
    94. }
    95. void mysolve()
    96. {
    97. cin>>n>>q;
    98. string s;
    99. cin>>s;
    100. for(int i=0; i1]=s[i]-'A';
    101. build(1,n,1);
    102. int l,r,k,op;
    103. while(q--)
    104. {
    105. cin>>op>>l>>r;
    106. if(op==1)update(l,r,1);
    107. else
    108. {
    109. cin>>k;
    110. int cnt=ask(l,r,1);
    111. cout<<C(r-l-cnt,k-1-cnt)<
    112. }
    113. }
    114. }
    115. int32_t main()
    116. {
    117. std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    118. pre[0]=1;
    119. int nx=1e5;
    120. for(int i=1; i<=nx; ++i)pre[i]=pre[i-1]*i%mod;
    121. dev[nx]=fastmi(pre[nx],mod-2)%mod;
    122. for(int i=nx-1; ~i; --i)dev[i]=dev[i+1]*(i+1)%mod;
    123. mysolve();
    124. system("pause");
    125. return 0;
    126. }

    Problem J. Mex Tree

    思路:

    1. 如果mex=n,显然答案为n
    2. 我们以val[i]=0的i设为根rt
    3. 显然mex=0时答案就是根节点的最大子树
    4. 其他情况,mex=k,显然val[i]=k的点不能包含,又必须包含小于k的所有点,显然我们答案就是取除k的子树之外的所有点(因为0点为根节点,k子树内的点与0相连必须经过k),如果k子树内存在点小于k,那么答案为0,如果都大于k,那么答案为n-sz[k](k子树大小)
    5. 因此,我们需要维护每个点的子树的包含的最小值
    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define endl "\n"
    5. #define int long long
    6. typedef pair<int, int> pii;
    7. //---------------------------------------------------------------------------------------------------------------------//
    8. //---------------------------------------------------------------------------------------------------------------------//
    9. //double 型memset最大127,最小128
    10. const int INF = 0x3f3f3f3f; //int型的INF
    11. const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
    12. const double eps=1e-9;
    13. const int N = 1e6 + 10;
    14. int a[N],sz[N],mn[N],mx[N],b[N];
    15. vector<int>edge[N];
    16. void dfs(int u,int f)
    17. {
    18. sz[u]=1,mn[u]=a[u];
    19. mx[u]=0;
    20. for(auto v:edge[u])if(v!=f)
    21. {
    22. dfs(v,u);
    23. mx[u]=max(mx[u],sz[v]);
    24. sz[u]+=sz[v];
    25. mn[u]=min(mn[u],mn[v]);
    26. }
    27. }
    28. void mysolve()
    29. {
    30. int n;
    31. cin>>n;
    32. int rt;
    33. for(int i=1; i<=n; ++i)
    34. {
    35. cin>>a[i];
    36. b[a[i]]=i;
    37. if(a[i]==0)rt=i;
    38. }
    39. int x;
    40. for(int i=2; i<=n; ++i)cin>>x,edge[x].push_back(i),edge[i].push_back(x);
    41. dfs(rt,-1);
    42. cout<" ";
    43. for(int i=1; i
    44. {
    45. if(mn[b[i]]>=i)cout<" ";
    46. else cout<<"0 ";
    47. }
    48. cout<
    49. }
    50. int32_t main()
    51. {
    52. std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    53. ll t=1;
    54. //cin >> t;
    55. while (t--)
    56. {
    57. mysolve();
    58. }
    59. system("pause");
    60. return 0;
    61. }

  • 相关阅读:
    shell 实例:检查default路由的存在
    2021第7届中国大学生程序设计竞赛CCPC广州站, 签到题4题
    Mybatis快速上手
    Linux用户/用户组管理
    branch与tag
    精英反向黄金正弦鲸鱼算法-附代码
    Vue项目的部署(服务器)
    16位、32位、64位系统字节长度
    喜报 | 祝贺璞华科技通过CMMI Lv5 等级复审!
    【LeetCode】891.子序列宽度之和
  • 原文地址:https://blog.csdn.net/WQhuanm/article/details/130845216