题目

发现自己一年之前非常垃圾

题目大意是给你一个\(n\)个点的环,给每个点一个\([1,a_i]\)的取值,并且满足环上任意相连两点权值不能相等,求方案数

考虑断环为链,发现不大会

不妨考虑所有\(a_i\)均相等的情况,设\(m=a_i\)

对于第一个点,有\(m\)种选择,其后每一个点的取值都不能和上一个相等,即\(m-1\)种选择,于是整个环就是\(m(m-1)^{n-1}\)

吗?

显然不是,这样我们不能保证\(1\)号点和\(n\)号点的取值不相等。设\(f_i\)表示\(1\)号点恰好和\(n-i+1\)到\(n\)号点取值相等的情况,我们算的\(m(m-1)^{n-1}\)其实等于\(f_0+f_1\)

考虑如何消掉\(f_1\),我们可以强行将\(n\)和\(1\)取值相同,其余点还是不能和前一个点取值相等,方案数是\(m(m-1)^{n-2}=f_1+f_2\);更一般的\(m(m-1)^{n-i}=f_{i-1}+f_i\),但是有一个特殊情况,即\(m(m-1)=f_{n-2}\),即让\(3\)号点到\(n\)号点都和\(1\)号点取值相等,这样\(2\)号点和\(1\)不相同自然就不会和后面的点相同。

我们要求的是\(f_0\),我们发现\(f_0+f_1-(f_1+f_2)+f_2+f_3-....-f_{n-2}+f_{n-2}=f_0\),即我们配一个\(-1\)的容斥系数即能求出\(f_0\)。

于是我们利用这个容斥就能断环为链,所以我们来考虑更一般的链上问题,即\(a_i\)不同的情况。

有一个显然的暴力\(dp\),设\(dp_{i,j}\)表示第\(i\)个点取值为\(j\)的方案数,\(s_i=\sum_{j=1}^{a_i}dp_{i,j}\),转移显然有\(dp_{i,j}=s_{i-1}-dp_{i-1,j}\)

由于我们的容斥本质上是使得最后连续的一段和\(1\)取值相等,这一段连续的取值受限于这一段中\(a_i\)的最小值,于是我们不妨选一个\(a_i\)最小的点作为一号点,这样每次\(dp\)的初值就不会改变,只需做一次\(dp\)即可。

考虑优化这个\(dp\)

当\(a_i>a_{i-1}\)的时候,对于\(\forall j\in [1,a_{i-1}]\)有\(dp_{i,j}=s_{i-1}-dp_{i-1,j}\);当\(j>a_{i-1}\)的时候,由于\(dp_{i-1,j}=0\),所以对于\(j\in(a_{i-1},a_i]\)有\(dp_{i,j}=s_{i-1}\)

当\(a_{i}<a_{i-1}\)的时候,对于\(\forall j\in [1,a_{i}]\)有\(dp_{i,j}=s_{i-1}-dp_{i-1,j}\);当\(j>a_i\)的时候,则有\(dp_{i,j}=0\)

不难发现这几个转移我们只需要一个能够支持区间取反、区间加以及区间覆盖的数据结构就能维护,于是直接使用线段树来整体dp即可。

由于\(a_i\)比较大,所以得动态开点,复杂度是\(O(n\log a_i)\)只能有\(80pts\)

代码

  1. #include<bits/stdc++.h>
  2. #define re register
  3. #define max(a,b) ((a)>(b)?(a):(b))
  4. #define min(a,b) ((a)<(b)?(a):(b))
  5. #pragma GCC optimize(3)
  6. #pragma GCC optimize("-fcse-skip-blocks")
  7. inline int read() {
  8. char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
  9. while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
  10. }
  11. const int mod=1e9+7;
  12. const int M=7e7+5;
  13. const int maxn=1e6+5;
  14. int n,a[maxn],f[maxn],b[maxn],pos,mx,rt;
  15. inline int qm(int x) {return x>=mod?x-mod:x;}
  16. int l[M],r[M],gt[M],jt[M],sum[M],cnt;
  17. bool ft[M];
  18. inline void pushdown(int now,int lx,int ry) {
  19. int mid=lx+ry>>1;
  20. int lenl=mid-lx+1,lenr=ry-mid;
  21. if(gt[now]!=-1) {
  22. if(!l[now]) l[now]=++cnt;
  23. if(!r[now]) r[now]=++cnt;
  24. gt[l[now]]=gt[r[now]]=gt[now];
  25. sum[l[now]]=1ll*gt[now]*lenl%mod;
  26. sum[r[now]]=1ll*gt[now]*lenr%mod;
  27. ft[l[now]]=ft[r[now]]=jt[l[now]]=jt[r[now]]=0;
  28. gt[now]=-1;
  29. }
  30. if(ft[now]) {
  31. if(!l[now]) l[now]=++cnt;
  32. if(!r[now]) r[now]=++cnt;
  33. ft[l[now]]^=1;ft[r[now]]^=1;
  34. sum[l[now]]=qm(mod-sum[l[now]]);
  35. sum[r[now]]=qm(mod-sum[r[now]]);
  36. jt[l[now]]=qm(mod-jt[l[now]]);
  37. jt[r[now]]=qm(mod-jt[r[now]]);
  38. ft[now]=0;
  39. }
  40. if(jt[now]) {
  41. if(!l[now]) l[now]=++cnt;
  42. if(!r[now]) r[now]=++cnt;
  43. sum[l[now]]=qm(sum[l[now]]+1ll*jt[now]*lenl%mod);
  44. sum[r[now]]=qm(sum[r[now]]+1ll*jt[now]*lenr%mod);
  45. jt[l[now]]=qm(jt[l[now]]+jt[now]);
  46. jt[r[now]]=qm(jt[r[now]]+jt[now]);
  47. jt[now]=0;
  48. }
  49. }
  50. int gan(int now,int x,int y,int lx,int ry,int v) {
  51. if(!now) now=++cnt,gt[now]=-1;
  52. if(x<=lx&&y>=ry) {
  53. sum[now]=1ll*v*(ry-lx+1)%mod;
  54. gt[now]=v;ft[now]=0;jt[now]=0;
  55. return now;
  56. }
  57. pushdown(now,lx,ry);
  58. int mid=lx+ry>>1;
  59. if(x<=mid) l[now]=gan(l[now],x,y,lx,mid,v);
  60. if(y>mid) r[now]=gan(r[now],x,y,mid+1,ry,v);
  61. sum[now]=qm(sum[l[now]]+sum[r[now]]);
  62. return now;
  63. }
  64. int jia(int now,int x,int y,int lx,int ry,int v) {
  65. if(!now) now=++cnt,gt[now]=-1;
  66. if(x<=lx&&y>=ry) {
  67. sum[now]=qm(sum[now]+1ll*v*(ry-lx+1)%mod);
  68. jt[now]=qm(jt[now]+v);
  69. return now;
  70. }
  71. pushdown(now,lx,ry);
  72. int mid=lx+ry>>1;
  73. if(x<=mid) l[now]=jia(l[now],x,y,lx,mid,v);
  74. if(y>mid) r[now]=jia(r[now],x,y,mid+1,ry,v);
  75. sum[now]=qm(sum[l[now]]+sum[r[now]]);
  76. return now;
  77. }
  78. int qufan(int now,int x,int y,int lx,int ry) {
  79. if(!now) now=++cnt,gt[now]=-1;
  80. if(x<=lx&&y>=ry) {
  81. sum[now]=qm(mod-sum[now]);
  82. ft[now]^=1;jt[now]=qm(mod-jt[now]);
  83. return now;
  84. }
  85. pushdown(now,lx,ry);
  86. int mid=lx+ry>>1;
  87. if(x<=mid) l[now]=qufan(l[now],x,y,lx,mid);
  88. if(y>mid) r[now]=qufan(r[now],x,y,mid+1,ry);
  89. sum[now]=qm(sum[l[now]]+sum[r[now]]);
  90. return now;
  91. }
  92. int main() {
  93. n=read();
  94. for(re int i=1;i<=n;i++) a[i]=read();
  95. pos=1;for(re int i=2;i<=n;i++) if(a[i]<a[pos]) pos=i;
  96. for(re int i=1;i<=n;i++) {
  97. b[i]=a[pos++];
  98. if(pos>n) pos=1;
  99. }
  100. for(re int i=1;i<=n;i++) mx=max(mx,a[i]);
  101. f[1]=b[1];rt=gan(rt,1,b[1],1,mx,1);
  102. for(re int i=2;i<=n;++i) {
  103. if(b[i-1]<b[i]) {
  104. rt=qufan(rt,1,b[i-1],1,mx);
  105. rt=jia(rt,1,b[i],1,mx,f[i-1]);
  106. }
  107. else {
  108. rt=qufan(rt,1,b[i],1,mx);
  109. rt=jia(rt,1,b[i],1,mx,f[i-1]);
  110. if(b[i]+1<=b[i-1]) rt=gan(rt,b[i]+1,b[i-1],1,mx,0);
  111. }
  112. f[i]=sum[rt];
  113. }
  114. int ans=0;
  115. for(re int i=n;i>=2;--i)
  116. if((n-i+1)&1) ans=qm(ans+f[i]);
  117. else ans=qm(ans-f[i]+mod);
  118. printf("%d\n",ans);
  119. return 0;
  120. }

正解也就是容斥+dp,但是容斥方法好像不太一样,就直接丢链跑了

正解

【牛客提高训练营2B】分糖果的更多相关文章

  1. 【牛客提高训练营5A】同余方程

    题目 吉老师的题做不动啊 首先\([l_1,r_1],[l_2,r_2]\)并不是非常好做,我们考虑将其拆成前缀信息 设\(solve(n,m)=\sum_{i=0}^n\sum_{j=0}^m[m| ...

  2. 【牛客提高训练营5B】旅游

    题目 吉老师的题时过一年还是不会做 从\(1\)号点出发经过每条边至少一次并且还要回到\(1\)号点,这跟欧拉回路的条件非常像,但是欧拉回路的实际上是"经过每一条边恰好一次并且回到出发点&q ...

  3. 牛客网——G送分了(py)

    链接:https://www.nowcoder.net/acm/contest/74/G来源:牛客网 题目描述 杭州人称傻乎乎的人为62,而嘟嘟家这里没有这样的习俗. 相比62,他那里的人更加讨厌数字 ...

  4. 牛客提高D6t3 分班问题

    分析 就就就是推柿子 看官方题解吧/px 代码 #include<iostream> #include<cstdio> #include<cstring> #inc ...

  5. 牛客提高D4t2 卖羊驼

    分析 不难想到dp[i][j]表示前i个数分了j组的最大值 我们发现这个dp状态有决策单调性 g[i][j]表示对于第i个数它的第j位最近出现的位置 每次一定从这些点转移 预处理即可 似乎还可以做到1 ...

  6. 牛客寒假训练营3 B 处女座的比赛资格(拓扑排序+最短路)

    题目链接 这个题,一眼看上去就是最短路的题,边权有负环显然不能用dij,然后出题人又卡了spfa,,那怎么办的想点办法啊,好像还有一个拓扑排序可以求最短路吧,这时候正解就已经得到了,就是拓扑排序求最短 ...

  7. 牛客提高集训营6 C 树(树链剖分)

    题目链接 为了纪(zhuang)念(bi)写完这个树剖单独写一篇.感觉还好,也就6k嘛. 完整比赛题解:https://www.cnblogs.com/SovietPower/p/9826829.ht ...

  8. 牛客提高R5 A.同余方程

    题意 题目链接 Sol 设\(solve(x, y)\)表示\(i \in [0, x], j \in [0, y]\)满足题目要求的方案数 首先容斥一下,\(ans = solve(r_1, r_2 ...

  9. 牛客提高D6t2 破碎的序列

    分析 我们不难发现对于偶数的情况只要相邻两个数不相等即可 而对于奇数的情况只要中间恰好隔一个数的两个数不相等即可 于是我们又dp[i][0/1]表示考虑到第i位,这一位和它后面离它最近的一个确定的数是 ...

随机推荐

  1. upc组队赛5 Bulbs

    Bulbs 题目描述 Greg has an m × n grid of Sweet Lightbulbs of Pure Coolness he would like to turn on. Ini ...

  2. PAT甲级——A1152 GoogleRecruitment【20】

    In July 2004, Google posted on a giant billboard along Highway 101 in Silicon Valley (shown in the p ...

  3. submlie 配置php运行

    选择 "工具" -- "编译系统" -- "新编译系统"(英文版对应为 "Tools" -- "Build S ...

  4. 将excle表中得数据生成insert语句插入到数据库中

    第一步:输入公式 第二步:拽住右下角得+往下拖拽

  5. python基础【第六篇】

    list列表 基本结构 lst =[1,2,3,5,6] 为什么学列表? 列表能够存储比字符串更多的数据 列表能够存储各种数据类型 列表的注意点 列表是有序的 列表是可变的,支持索引,切片,步 切片后 ...

  6. python- 粘包 struct,socketserver

    黏包 黏包现象 让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd) res=subprocess.Popen(cmd.decode('utf-8'), sh ...

  7. CG-CTF misc部分wp

    将Misc剥离出来了,已完结(coding gay不想做了) MISC1,图种一听图种,现将图片的GIF改为zip,然后解压得到另一张动图看动图最后一句话为‘都深深的出卖了我’,得到 flag2, 丘 ...

  8. Javascript权威指南——读书笔记

    一.JavaScript核心语法 1.字符串中接受RegExp参数的方法 (1)text.search(pattern)返回首次匹配成功的位置 (2)text.match(pattern)返回匹配组成 ...

  9. ASE——第一次结对作业

    ASE--第一次结对作业 问题定义 很早就听说了MSRA的黄金点游戏,让大家写Bot来参加比赛看谁的AI比较聪明可以操盘割韭菜.深感ASE课程老师设计的任务太用心了,各种接口都准备好了,大家只用专注于 ...

  10. spring security学习总结

    这几天一直在学习spring security的相关知识.逛各大论坛,看相关api与教学视频,获益良多! 简介 Spring Security是为基于Spring的企业应用系统提供声明式的安全访问控制 ...