可以说是第一场AGC了,做了三道题之后还有30min,杠了一下D题发现杠不出来,三题滚粗了

rating起步1300+,感觉还是很菜。。。

只有三题水平显然以后还会疯狂--啊(CF的惨痛经历)

改题的感觉似乎还不错因为思维都非常的妙(我根本想不到)

A - Zero-Sum Ranges

开场娱乐大家的小水题,区间和为0的情况存在于sum[R] == sum[L - 1],只要记录一下某一个值的sum出现了多少次就行,懒得离散化直接用map就OK啊

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <map>
  6. #define MAXN 200005
  7. #define PLI pair<long long,int>
  8. #define fi first
  9. #define se second
  10. #define mp make_pair
  11. //#define ivorysi
  12. using namespace std;
  13. typedef long long int64;
  14. int N;
  15. int64 A[MAXN];
  16. map<int64,int> mmm;
  17. void Solve() {
  18. scanf("%d",&N);
  19. for(int i = 1 ; i <= N ; ++i) scanf("%lld",&A[i]);
  20. mmm[0] = 1;
  21. int64 ans = 0;
  22. for(int i = 1 ; i <= N ; ++i) {
  23. A[i] += A[i - 1];
  24. ans += mmm[A[i]];
  25. mmm[A[i]] += 1;
  26. }
  27. printf("%lld\n",ans);
  28. }
  29. int main() {
  30. #ifdef ivorysi
  31. freopen("f1.in","r",stdin);
  32. #endif
  33. Solve();
  34. return 0;
  35. }

B - Find Symmetries

把矩阵行循环平移x,列循环平移y后,矩阵关于左上到右下这条对角线对称

矩阵大小是300

然后我就写了个暴力然而我并没发现我的暴力是\(n^4\)然后愉快TLE

我就开始想着优化,发现固定行平移,每平移一列hash值的更改可以O1算出来,check把每行每列hash起来比较,是O(n)的,然后过掉了

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <map>
  6. #define MAXN 200005
  7. #define PLI pair<long long,int>
  8. #define fi first
  9. #define se second
  10. #define mp make_pair
  11. #define ha 99994711
  12. #define ba 823
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long int64;
  16. int N;
  17. char s[305][305],b[305][305];
  18. int64 hc[305],hr[305],e;
  19. inline int C(int x) {
  20. return x > N ? x - N : x;
  21. }
  22. bool check(int y) {
  23. int T = C(N + y);
  24. for(int i = 1 ; i <= N ; ++i)
  25. hr[i] = (hr[i] * ba + (b[i][T] - 'a' + 1)) % ha;
  26. for(int i = 1 ; i <= N ; ++i) {
  27. if(hr[i] != hc[C(i + y)]) {
  28. T = C(N + y + 1);
  29. for(int j = 1 ; j <= N ; ++j)
  30. hr[j] = (hr[j] - e * (b[j][T] - 'a' + 1) % ha + ha) % ha;
  31. return false;
  32. }
  33. }
  34. T = C(N + y + 1);
  35. for(int i = 1 ; i <= N ; ++i)
  36. hr[i] = (hr[i] - e * (b[i][T] - 'a' + 1) % ha + ha) % ha;
  37. return true;
  38. }
  39. void Solve() {
  40. scanf("%d",&N);
  41. if(N == 1) {
  42. puts("1");return;
  43. }
  44. e = 1;
  45. for(int i = 1 ; i < N ; ++i) e = e * ba % ha;
  46. for(int i = 1 ; i <= N ; ++i) {
  47. scanf("%s",s[i] + 1);
  48. }
  49. int cnt = 0;
  50. for(int A = 0 ; A < N ; ++A) {
  51. memset(hc,0,sizeof(hc));
  52. memset(hr,0,sizeof(hr));
  53. for(int i = 1 ; i <= N ; ++i) {
  54. for(int j = 1 ; j <= N ; ++j) {
  55. b[i][j] = s[C(i + A)][j];
  56. hc[j] = (hc[j] * ba + (b[i][j] - 'a' + 1)) % ha;
  57. if(j != N) {
  58. hr[i] = (hr[i] * ba + (b[i][j] - 'a' + 1)) % ha;
  59. }
  60. }
  61. }
  62. for(int B = 0 ; B < N ; ++B) {
  63. if(check(B)) ++cnt;
  64. }
  65. }
  66. printf("%d\n",cnt);
  67. }
  68. int main() {
  69. #ifdef ivorysi
  70. freopen("f1.in","r",stdin);
  71. #endif
  72. Solve();
  73. return 0;
  74. }

C - Painting Machines

while(1) 推式子

联想到地震后的幻想乡显然题目可以转化为

\(\sum_{i = 0}^{N - 2} T(i)\)其中\(T(i)\)表示用了i次操作没有全部染黑的方案数

有\(T(0) = (N - 1)!\)

然后分类讨论,一个是因为没用N-1而没有全部染黑的方案数是\(\binom{N - 2}{i}i!\)

如果用了N - 1,那么方案是\((\binom{N - 2}{i - 1} - W(i - 1))i!\)

\(W(i)\)表示用了一个N - 1号机器和其他i个机器,把所有方格染黑了的方案数

显然序列里会有1

把序列差分一下,会发现这个序列不是1就是2,也就是一堆1和一堆2的数目固定,一堆1和一堆2的和是N - 2,这是个二元一次方程,然后求出了1的个数和2的个数,就是个带重复元素的全排列,答案是

\(\frac{(num_1 + num_2)! }{num_1 ! num_2 !}\)

其他\(N - 1 - i\)台机器随意排列,最后还要乘上\((N - i - 1)!\)

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <map>
  6. #define MAXN 1000005
  7. #define PLI pair<long long,int>
  8. #define fi first
  9. #define se second
  10. #define mp make_pair
  11. #define ha 99994711
  12. #define ba 823
  13. #define MOD 1000000007
  14. //#define ivorysi
  15. using namespace std;
  16. typedef long long int64;
  17. int64 fac[MAXN],invfac[MAXN],ans;
  18. int N;
  19. int64 fpow(int64 x,int64 c) {
  20. int64 res = 1,t = x;
  21. while(c) {
  22. if(c & 1) res = res * t % MOD;
  23. t = t * t % MOD;
  24. c >>= 1;
  25. }
  26. return res;
  27. }
  28. int64 C(int n,int m) {
  29. if(n < m) return 0;
  30. return fac[n] * invfac[m] % MOD * invfac[n - m] % MOD;
  31. }
  32. int64 W(int k) {
  33. int x = N - 2 - k;
  34. int y = k - x;
  35. if(x < 0 || y < 0) return 0;
  36. return fac[k] * invfac[y] % MOD * invfac[x] % MOD;
  37. }
  38. void Solve() {
  39. scanf("%d",&N);
  40. if(N == 2) {
  41. puts("1");
  42. return;
  43. }
  44. fac[0] = invfac[0] = 1;
  45. for(int i = 1 ; i <= N ; ++i) {
  46. fac[i] = fac[i - 1] * i % MOD;
  47. }
  48. invfac[N] = fpow(fac[N],MOD - 2);
  49. for(int i = N - 1 ; i >= 1 ; --i) {
  50. invfac[i] = invfac[i + 1] * (i + 1) % MOD;
  51. }
  52. ans += fac[N - 1];
  53. for(int i = 1 ; i < N - 1 ; ++i) {
  54. ans += (C(N - 2,i) + C(N - 2,i - 1) + MOD - W(i - 1))* fac[i] % MOD * fac[N - 1 - i] % MOD;
  55. ans %= MOD;
  56. }
  57. printf("%lld\n",ans);
  58. }
  59. int main() {
  60. #ifdef ivorysi
  61. freopen("f1.in","r",stdin);
  62. #endif
  63. Solve();
  64. return 0;
  65. }

D - Go Home

题解

神仙博弈题(其实也不算博弈)

你看完题,发现,啥,最优决策,咋最优啊,啥最优啊,什么玩意,弃疗吧……

题解是这么说的,如果汽车在1 和N中间,且\(A_1 >= A_n\),那么N肯定会投票给1,为什么,因为赢不了,如果暂时让车靠近了N,最后也会因为N - 1公寓里的人都回家了而车也再回到1,所以为了早回家,N的票都会给1,且最后的操作一定会有一个\(X_{n} - X_{1}\)的长度,那么我们把N的票全部给1,\(P_{1} += P_{N}\)也没有问题,如果\(A_{n} > A_{1}\)是类似的,之后就变成了1和N - 1之间的子问题……停止条件是所有公寓都在初始位置\(S\)的一边

累加答案的话要注意和前一次操作方向相反才累加,如果前一次1 - N,下一次1 - (N - 1),第二次的距离不用累加进答案

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #define MAXN 100005
  4. //#define ivorysi
  5. using namespace std;
  6. typedef long long int64;
  7. typedef double db;
  8. int N;
  9. int64 S,X[MAXN],P[MAXN],ans;
  10. void Solve() {
  11. scanf("%d%lld",&N,&S);
  12. for(int i = 1 ; i <= N ; ++i) {
  13. scanf("%lld%lld",&X[i],&P[i]);
  14. }
  15. int L = 1,R = N;
  16. int dir = 0;
  17. while(1) {
  18. if(X[L] >= S) {ans += X[R] - S;break;}
  19. if(X[R] <= S) {ans += S - X[L];break;}
  20. if(P[L] >= P[R]) {
  21. if(dir != 1) {dir = 1;ans += X[R] - X[L];}
  22. P[L] += P[R];R--;
  23. }
  24. else {
  25. if(dir != 2) {dir = 2;ans += X[R] - X[L];}
  26. P[R] += P[L];L++;
  27. }
  28. }
  29. printf("%lld\n",ans);
  30. }
  31. int main() {
  32. #ifdef ivorysi
  33. freopen("f1.in","r",stdin);
  34. #endif
  35. Solve();
  36. return 0;
  37. }

E - Inversions

我觉得这道题计算排列的方法应该算个比较重要前置技能,但这又不是什么板啥的,如果知道了这个子问题那么这道题至少会有头绪

如何计算每个数位有限制的排列总个数?

先计算一个\(cnt[k]\)表示可以填k的位置的个数,可以用一个后缀和算出来

答案就是\(\prod_{i = 1}^{N} cnt[i] - (N - i)\)

有了这个我们再来看这道题

我们对于两个位置\(i < j\)且\(A_{i} <= A_{j}\)计算\(i\)位置上的数大于\(j\)位置上的数的排列的总和,我们可以让\(A_{j} = A_{i}\),然后计算排列个数,再除二就是答案

以下的\(cnt[i]\)更改成\(cnt[i] - (N - i)\)

这样的话我们考虑更改\(A_{j}\)会使得\([A_{i} + 1,A_{j}]\)这个区间的cnt减1,也就是乘上了\((cnt[i] - 1) / cnt[i]\),也就是处理成区间前缀乘积后相除,然而会发现处理0的情况比较特殊,还需要记录前缀出现了几个0,前缀上0个数相同值才不为0,位置增加0的个数单调不减,所以可以预处理出来每一段开始位置和结束位置

\(A_{i} > A_{j}\)我们发现就是把\(A_{i} := A_{j}\)后总排列数减去计算出的新排列值的一半

以上两种情况都可以用树状数组快速维护

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #define MAXN 200005
  5. //#define ivorysi
  6. using namespace std;
  7. typedef long long int64;
  8. typedef double db;
  9. const int MOD = 1000000007;
  10. int N,A[MAXN],x[MAXN],st[MAXN],ed[MAXN];
  11. int64 cnt[MAXN],V[MAXN],D[MAXN],ID[MAXN],S,tr[MAXN],tr_cnt[MAXN],Inv_2,ans;
  12. int64 fpow(int64 x,int64 c) {
  13. int64 res = 1,t = x;
  14. while(c) {
  15. if(c & 1) res = res * t % MOD;
  16. t = t * t % MOD;
  17. c >>= 1;
  18. }
  19. return res;
  20. }
  21. int lowbit(int x) {return x & (-x);}
  22. void insert(int x,int64 v) {
  23. while(x <= N) {
  24. tr[x] += v;
  25. tr[x] %= MOD;
  26. tr_cnt[x]++;
  27. x += lowbit(x);
  28. }
  29. }
  30. int64 Query(int x,int64 v) {
  31. int64 res = 0;
  32. while(x > 0) {
  33. res += tr[x];
  34. x -= lowbit(x);
  35. }
  36. res %= MOD;
  37. return res * v % MOD;
  38. }
  39. int64 getnum(int x) {
  40. int64 res = 0;
  41. while(x > 0) {
  42. res += tr_cnt[x];
  43. x -= lowbit(x);
  44. }
  45. return res;
  46. }
  47. int64 Query_range(int L,int R,int64 v) {
  48. if(L == 0) ++L;
  49. if(L > R) return 0;
  50. return (Query(R,v) + MOD - Query(L - 1,v)) % MOD;
  51. }
  52. void Solve() {
  53. scanf("%d",&N);
  54. for(int i = 1 ; i <= N ; ++i) scanf("%d",&A[i]),cnt[A[i]]++;
  55. for(int i = N - 1; i >= 1 ; --i) cnt[i] += cnt[i + 1];
  56. S = 1;Inv_2 = (MOD + 1) / 2;
  57. for(int i = 1 ; i <= N ; ++i) {
  58. cnt[i] -= N - i;
  59. if(cnt[i] <= 0) {puts("0");return;}
  60. S = S * cnt[i] % MOD;
  61. }
  62. for(int i = 1 ; i <= N ; ++i) {
  63. V[i] = (cnt[i] - 1) * fpow(cnt[i],MOD - 2) % MOD;
  64. }
  65. D[0] = 1;
  66. st[0] = 0;
  67. for(int i = 1 ; i <= N ; ++i) {
  68. x[i] = x[i - 1];D[i] = D[i - 1];
  69. if(V[i] == 0) {x[i]++;st[x[i]] = i;ed[x[i] - 1] = i - 1;}
  70. else D[i] = D[i] * V[i] % MOD;
  71. ID[i] = fpow(D[i],MOD - 2);
  72. }
  73. ed[x[N]] = N;
  74. for(int i = 1 ; i <= N ; ++i) {
  75. ans += Query_range(st[x[A[i]]],A[i],D[A[i]] * S % MOD * Inv_2 % MOD);
  76. ans %= MOD;
  77. insert(A[i],ID[A[i]]);
  78. }
  79. memset(tr,0,sizeof(tr));
  80. memset(tr_cnt,0,sizeof(tr_cnt));
  81. for(int i = 1 ; i <= N ; ++i) {
  82. int64 t = Query_range(A[i] + 1,ed[x[A[i]]],ID[A[i]] * S % MOD * Inv_2 % MOD);
  83. ans += ((getnum(N) - getnum(A[i])) * S % MOD + MOD - t) % MOD;
  84. ans %= MOD;
  85. insert(A[i],D[A[i]]);
  86. }
  87. printf("%lld\n",ans);
  88. }
  89. int main() {
  90. #ifdef ivorysi
  91. freopen("f1.in","r",stdin);
  92. #endif
  93. Solve();
  94. return 0;
  95. }

F - 01 on Tree

题解

这个是真的神仙题。。。

脑子里一直是某个按子树大小的贪心,然后一直被叉掉

最后说是初始化每个节点就是一个单独的树,记录这个树里1的个数和0,初始的时候1的个数即为节点值是否为1,0的个数即为节点值是否为0

我们按照\(C_{0i}/C_{1i}\)排序,并把每个点和直接父亲接起来,意思就是把这个点的0和1接在父亲节点的后面,多出来的贡献即是

v是儿子,p是父亲,\(C_{1p} * C_{0v}\)

推一下式子可以证出来选别的儿子肯定不优

然后更新父亲p的值,也就是p变成了一个新的树,这个可以用并查集维护

然后带更新的排序用一个set实现就可以

神仙题神仙题。。。

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <vector>
  4. #include <set>
  5. #include <cstring>
  6. #define MAXN 200005
  7. //#define ivorysi
  8. using namespace std;
  9. typedef long long int64;
  10. typedef double db;
  11. int N,P[MAXN],V[MAXN],fa[MAXN],C[2][MAXN];
  12. int getfa(int x) {
  13. return fa[x] == x ? x : fa[x] = getfa(fa[x]);
  14. }
  15. struct cmp {
  16. bool operator() (const int &a,const int &b) {
  17. if(1LL * C[0][a] * C[1][b] != 1LL * C[0][b] * C[1][a])
  18. return 1LL * C[0][a] * C[1][b] > 1LL * C[0][b] * C[1][a];
  19. else return a > b;
  20. }
  21. };
  22. multiset<int,cmp> S;
  23. void Solve() {
  24. scanf("%d",&N);
  25. for(int i = 2 ; i <= N ; ++i) scanf("%d",&P[i]);
  26. for(int i = 1 ; i <= N ; ++i) scanf("%d",&V[i]);
  27. for(int i = 1 ; i <= N ; ++i) fa[i] = i;
  28. for(int i = 1 ; i <= N ; ++i) C[V[i]][i] = 1;
  29. for(int i = 2 ; i <= N ; ++i) S.insert(i);
  30. int64 ans = 0;
  31. for(int i = 1 ; i <= N - 1 ; ++i) {
  32. int v = *S.begin();
  33. int p = getfa(P[v]);
  34. S.erase(v);S.erase(p);
  35. ans += 1LL * C[0][v] * C[1][p];
  36. C[1][p] += C[1][v];C[0][p] += C[0][v];
  37. fa[v] = p;
  38. if(p != 1) S.insert(p);
  39. }
  40. printf("%lld\n",ans);
  41. }
  42. int main() {
  43. #ifdef ivorysi
  44. freopen("f1.in","r",stdin);
  45. #endif
  46. Solve();
  47. return 0;
  48. }

【AtCoder】AGC023 A-F题解的更多相关文章

  1. AtCoder Beginner Contest 238 A - F 题解

    AtCoder Beginner Contest 238 \(A - F\) 题解 A - Exponential or Quadratic 题意 判断 \(2^n > n^2\)是否成立? S ...

  2. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  3. AtCoder Beginner Contest 154 题解

    人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We ...

  4. AtCoder Beginner Contest 153 题解

    目录 AtCoder Beginner Contest 153 题解 A - Serval vs Monster 题意 做法 程序 B - Common Raccoon vs Monster 题意 做 ...

  5. AtCoder Beginner Contest 177 题解

    AtCoder Beginner Contest 177 题解 目录 AtCoder Beginner Contest 177 题解 A - Don't be late B - Substring C ...

  6. AtCoder Beginner Contest 184 题解

    AtCoder Beginner Contest 184 题解 目录 AtCoder Beginner Contest 184 题解 A - Determinant B - Quizzes C - S ...

  7. AtCoder Beginner Contest 173 题解

    AtCoder Beginner Contest 173 题解 目录 AtCoder Beginner Contest 173 题解 A - Payment B - Judge Status Summ ...

  8. AtCoder Beginner Contest 172 题解

    AtCoder Beginner Contest 172 题解 目录 AtCoder Beginner Contest 172 题解 A - Calc B - Minor Change C - Tsu ...

  9. AtCoder Beginner Contest 169 题解

    AtCoder Beginner Contest 169 题解 这场比赛比较简单,证明我没有咕咕咕的时候到了! A - Multiplication 1 没什么好说的,直接读入两个数输出乘积就好了. ...

  10. AtCoder Beginner Contest 148 题解

    目录 AtCoder Beginner Contest 148 题解 前言 A - Round One 题意 做法 程序 B - Strings with the Same Length 题意 做法 ...

随机推荐

  1. 科学计算三维可视化---Mlab基础(改变物体的外观颜色)

    import numpy as np from mayavi import mlab #建立数据 x,y = np.mgrid[-::200j,-::200j] z = *np.sin(x*y)/(x ...

  2. 【数据库-MySql】清空所有表格的所有数据

    方式一. drop procedure if exists del_all_tb; delimiter $$ create procedure del_all_tb(db char(20)) begi ...

  3. 蓝桥杯 地宫寻宝 DFS 动态规划

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstdl ...

  4. zookeeper图形工具——zkui

    虽然zookeeper安装包提供了客户端工具zkcli,但是命令特别少 ,每次想看看里面的节点信息特别费劲. 幸好有图形工具——zkui,https://github.com/echoma/zkui, ...

  5. CF 1008C Reorder the Array

    You are given an array of integers. Vasya can permute (change order) its integers. He wants to do it ...

  6. 【leetcode 简单】 第八十七题 两整数之和

    不使用运算符 + 和-,计算两整数a .b之和. 示例: 若 a = 1 ,b = 2,返回 3. class Solution: def getSum(self, a, b): "&quo ...

  7. Google Congestion Control介绍

    随着网络带宽的日益增加和便携式设备,如智能手机或平板电脑处理能力的增强,基于互联网的实时通信已经成为热点. 虽然视频会议已商用了多年,特别是SKYPE这样的视频应用在互联网上已有10年时间,但针对实时 ...

  8. 高性能.NET MVC之QMVC!

    ASP.NET!这个词代表者一个单词Fat!因为他总是捆绑着太多的太多的类,太多太多的各种功能!你也许会用到,如果你反编译或阅读他们开源的源码,你会不会犹如在大海中找不到方向?不管是Web form ...

  9. Jenkins无法安装插件或首次安装插件界面提示Offline

    一.首先点击系统管理 二.点击插件管理 三.选择高级管理 四.将升级站点中的https改成http即可

  10. c语言格式控制符

    http://zhidao.baidu.com/link?url=-YJjz3U0fd_eSW9eLa8ankGo_QbyOOOaKYWyAY9g4mKWQj0DN6l12OSLJz24U8jCwo1 ...