当前位置:   article > 正文

Codeforces Round 911 (Div. 2)(C dp D gcd 分解+容斥 E tarjan+dp)_codeforces round 919 (div. 2)c

codeforces round 919 (div. 2)c

A.手玩题:

可以通过最后一个样例,如果是长度为3的连续O,直接在两边放就行,然后一直用中间的水填到其他地方

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 3e5+10,mod= 998244353;
  4. #define int long long
  5. int n,m,k;
  6. void solve()
  7. {
  8. cin>>n;
  9. string s;
  10. cin>>s;
  11. s="?"+s;
  12. int res=0;
  13. int now=0;
  14. s+="#";
  15. for(int i=1;i<=n+1;i++){
  16. if(s[i]=='#')
  17. {
  18. if(now>=3){
  19. cout<<2<<"\n";
  20. return ;
  21. }
  22. res+=min(2ll,now);
  23. now=0;
  24. }
  25. else now++;
  26. }
  27. cout<<res<<"\n";
  28. }
  29. signed main()
  30. {
  31. cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
  32. int t=1;
  33. cin>>t;
  34. while(t--) solve();
  35. }

B:

直接每个数字都去判定能不能成为最后一个

假设都变成 a

然后目标变成 让 b c的数量相同

假设只操作b c,那么他们的差都减一,差奇偶性不变

如果操作a c或者a b,那么他们的差还是不变,因为-b -a ,+c,差变化2

所以如果差是奇数没法操作,

再想一下,那么对a的数量有没有啥要求呢

可以发现没要求,

因为b c可以操作自己变出一个a,然后再用 a去操作自己,他们可以独立自主

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 3e5+10,mod= 998244353;
  4. #define int long long
  5. int n,m,k;
  6. void solve()
  7. {
  8. int a,b,c;
  9. auto ok=[&](int a,int b,int c)
  10. {
  11. int need=abs(b-c);
  12. if(need%2==0) return true;
  13. return false;
  14. };
  15. cin>>a>>b>>c;
  16. if(ok(a,b,c)) cout<<"1 ";
  17. else cout<<"0 ";
  18. if(ok(b,a,c)) cout<<"1 ";
  19. else cout<<"0 ";
  20. if(ok(c,a,b)) cout<<"1 ";
  21. else cout<<"0 ";
  22. cout<<"\n";
  23. }
  24. signed main()
  25. {
  26. cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
  27. int t=1;
  28. cin>>t;
  29. while(t--) solve();
  30. }

C:

感觉很裸的dp

dp状态:通过u这个子树到达叶子节点的最少次数

那么如果是叶子节点无需代价

如果不是叶子节点,判断走的左右子树的方向和当前根方向是否相同,不同代价+1

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 3e5+10,mod= 998244353;
  4. #define int long long
  5. typedef long long LL;
  6. typedef pair<int, char> PII;
  7. int n,m,k;
  8. string s;
  9. vector<PII> g[N];
  10. int f[N];
  11. void dfs(int u){
  12. //if(s[u]=='U') f[u]=1;
  13. if(g[u].empty()){
  14. f[u]=0;return ;
  15. }
  16. for(auto [v,w]:g[u])
  17. {
  18. dfs(v);
  19. f[u]=min(f[u],f[v]+(w!=s[u]));
  20. }
  21. }
  22. void solve()
  23. {
  24. cin>>n>>s;
  25. s="?"+s;
  26. for(int i=1;i<=n;i++){
  27. g[i].clear();
  28. f[i]=2e18;
  29. }
  30. for(int i=1;i<=n;i++){
  31. int a,b;
  32. cin>>a>>b;
  33. if(a) g[i].emplace_back(a,'L');
  34. if(b) g[i].emplace_back(b,'R');
  35. }
  36. dfs(1);
  37. cout<<f[1]<<"\n";
  38. }
  39. signed main()
  40. {
  41. cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
  42. int t=1;
  43. cin>>t;
  44. while(t--) solve();
  45. }

D:

首先先排序,排序不影响答案

然后问题变成了

当前数(a[i]和前面数的gcd之和)*后面的个数(就是k嘛)

然后难点是前面

我们可以分开求a[x]的因数的贡献,

通过一个调和级数求1到10w的每个数的因子(不是质因子哦,而是因子,比如16的因子有1 2 4 8 16)

然后a[i]和前面数因子的贡献计算

这里举例说明一下

假设

a[i]=20 a[j]=4

a[i]的因子有 1 2 4 510 20 

a[j]因子有 1 2 4

那么他们gcd的贡献是gcd(20,4)=4

直接求他们里面最大的共同的的因子不好求(n^2超时间嘛)

但是我们知道每个数的因子最多就128个? n*128够了

然后我们可以求当前数的当前因子能和前面数的因子的总贡献

比如上面例子的1和1配对 2和2配对 4和4配对

但是注意到我们贡献其实只有一个4

那么咋办呢可以用容斥来解决

4的因子里面有2 1

2的因子有1

1的因子只有自己

所以我们求完后还要减去这个因子的倍数

设当前数组f[x]表示因子x有多少个(i,j)的对数

根据上面那个例子a[i]=20 a[j]=4

f[4]=1 f[2]=1 f[1]=1(因为只有两个数嘛,所以只有一对)

然后计算完这个f数组,我们要用容斥减去当前x的倍数的对数

比如上面例子的f[2]要减去f[4]  f[1]要减去f[1]减去f[2]减去f[4](这里的f[2]要先减去f[4]哦)

然后当前f[x]数组就是名副其实的因子是x的对数

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e5+10,mod= 998244353;
  4. #define int long long
  5. typedef long long LL;
  6. typedef pair<int, char> PII;
  7. int n,m,k;
  8. int a[N];
  9. vector<int> g[N];
  10. int gcd(int a,int b){
  11. return b?gcd(b,a%b):a;
  12. }
  13. void init(){
  14. for(int i=1;i<N;i++){
  15. for(int j=i;j<N;j+=i){
  16. g[j].push_back(i);
  17. }
  18. }
  19. }
  20. void solve()
  21. {
  22. cin>>n;
  23. for(int i=1;i<=n;i++){
  24. cin>>a[i];
  25. }
  26. sort(a+1,a+1+n);
  27. vector<int> c(N),f(N);
  28. for(int i=1;i<=n;i++)
  29. {
  30. for(auto x:g[a[i]]){
  31. f[x]+=c[x]*(n-i);
  32. c[x]++;
  33. }
  34. }
  35. int res=0;
  36. for(int i=100000;i>=1;i--){
  37. for(int j=i+i;j<=100000;j+=i){
  38. f[i]-=f[j];
  39. }
  40. res+=f[i]*i;
  41. }
  42. cout<<res<<"\n";
  43. }
  44. signed main()
  45. {
  46. cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
  47. int t=1;
  48. init();
  49. cin>>t;
  50. while(t--) solve();
  51. }

E:

手完可以发现如果是强联通分量最后会变成一个有向完全图

代表着如果进来了,因为要求路径最长,所以这个强联通分量的点都要走一遍且保证点不重复,

然后直接dp一下即可

然后因为是拓扑序大的 scc_cnt小,因为tarjan是先到底部的,底部的点会先缩,再回溯到上面缩,所以dp直接从1开始即可

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 3e5+10,mod= 998244353;
  4. #define int long long
  5. typedef long long LL;
  6. typedef pair<int, char> PII;
  7. int n,m,k;
  8. vector<int> g[N],h[N];
  9. int dfn[N],low[N];
  10. int scc_cnt,timestamp;
  11. int stk[N],id[N];
  12. bool in_stk[N];
  13. int sz[N];
  14. int top;
  15. stack<int> s;
  16. int b[N],a[N],c[N],f[N],gg[N];
  17. void tarjan(int u){
  18. dfn[u] = low[u] = ++ timestamp;
  19. stk[ ++ top] = u, in_stk[u] = true;
  20. for (auto j:g[u])
  21. {
  22. if (!dfn[j])
  23. {
  24. tarjan(j);
  25. low[u] = min(low[u], low[j]);
  26. }
  27. else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
  28. }
  29. if (dfn[u] == low[u])
  30. {
  31. ++ scc_cnt;
  32. int y;
  33. do {
  34. y = stk[top -- ];
  35. in_stk[y] = false;
  36. id[y] = scc_cnt;
  37. } while (y != u);
  38. }
  39. }
  40. void solve()
  41. {
  42. cin>>n>>m;
  43. scc_cnt=timestamp=top=0;
  44. for(int i=0;i<=n;i++){
  45. g[i].clear();
  46. dfn[i]=low[i]=0;
  47. in_stk[i]=false;
  48. h[i].clear();
  49. id[i]=b[i]=c[i]=0;
  50. f[i]=gg[i]=0;
  51. }
  52. for(int i=1;i<=n;i++) cin>>a[i];
  53. for(int i=1;i<=m;i++){
  54. int a,b;cin>>a>>b;
  55. g[a].push_back(b);
  56. }
  57. for(int i=1;i<=n;i++){
  58. if(!dfn[i])
  59. tarjan(i);
  60. }
  61. for(int i=1;i<=n;i++)
  62. {
  63. b[id[i]]+=a[i];
  64. c[id[i]]++;
  65. }
  66. for(int u=1;u<=n;u++){
  67. //cout<<id[u]<<" ";
  68. for(auto v:g[u]){
  69. if(id[u]!=id[v]){
  70. h[id[u]].push_back(id[v]);
  71. }
  72. }
  73. }
  74. int ans1=0,ans2;
  75. for(int i=1;i<=scc_cnt;i++){
  76. f[i]=c[i],gg[i]=b[i];
  77. for(auto j:h[i]){
  78. int t1=f[j]+c[i],t2=gg[j]+b[i];
  79. if(t1>f[i]||t1==f[i]&&t2<gg[i]){
  80. f[i]=t1,gg[i]=t2;
  81. }
  82. }
  83. if (f[i] > ans1 || f[i] == ans1 && gg[i] < ans2) ans1 = f[i], ans2 = gg[i];
  84. }
  85. cout<<ans1<<" "<<ans2<<"\n";
  86. }
  87. signed main()
  88. {
  89. cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
  90. int t=1;
  91. cin>>t;
  92. while(t--) solve();
  93. }

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

闽ICP备14008679号