题目大意:

  传送门

  给一个n个点的有向完全图(即任意两点有且仅有一条有向边)。

  每一个点上有$S_i$个人,开始时其中有些人有真金块,有些人没有金块。当时刻$i$时,若$u$到$v$有边,若$u$中第$i%S_u$个人有金块(无论真假),且$v$中第$i%S_v$个人没有金块,则会给$v$中第$i%S_v$个人一个假金块。

  假设这样传递了无数次。(即不会再满足上面的条件时)

  最后,拥有真金块的人一定可以把金子买出去,而拥有假的人有一半的概率买出去,每买出去一个会给自己的点贡献1的价值。

  问题是:对于每种所有人卖出金块的结果,卖出最多的前$a$个点中会等概率挑出$b$个点,每个不同的$b$的方案(即存在一个点x在方案一中出现而在方案二中没有出现,称为两个不同的方案)会给答案贡献1,求答案对$1e9+7$的余。

题解:

  二柱子找到的神题……(它和dp有什么关系……

  显然我们如果能求出最后每个点有多少假金子这就是一道组合裸体。

  先不考虑真假。

part1:

  考虑$u$对$v$的贡献。若u中第x个人有金子,则v中的y均会拥有金块,显然 

  即所有满足$y \equiv x \mod (s_v,s_u)$的y所有金子。这个推导很简单,把x移到左边然后贝祖定理就完了。

  即相当与把x映射到$(s_v,s_u)$的剩余系中。我们将其称为$u$对$v$的贡献,用$F(gcd,x)$来表示$u$的元素$x$在$gcd$剩余系下的结果

  当$v$又向$w$连边时,我们会发现x对w的贡献是每一个y直接贡献的,即   。

  类比$x$与$y$的关系我们知道$z\equiv y\mod (s_v,s_w)$。所有有贡献 

  再来思考$x$与$z$的关系。有一个显然的结果是$z\equiv x \mod \gcd (s_u,s_v,s_w)$。

  这个也很好证明:

  我们知道:设变量$a,b,c,d$满足$c|a,d|b$则会有$(c,d)|a+b$。

  我们令$c=(s_u,s_v),d=(s_v,s_w),a=x-y,d=y-z$。自然就可以得到这个关系了。

  同时我们再考虑是否所有满足这个关系的$z$一定会得到金块。

  即:通过$z$与$x$的关系和$z$与$y$的关系,构造出一个$y$使得能满足$y$与$x$的关系:

     

    

  这样我们就证明了逆定理的正确性。

  这用归纳法我们可以证明:设$u$到$v$的一条路径上,设路径上所有点的最大公约数为$gcd$,$u$上$x$对$v$的贡献为$F(gcd,x)$。

part2:

  可是当出现环呢?

  我们发现上面的结论时刻成立的,两点间的贡献只和路径$gcd$有关。环内两点的路径可以遍历环内每一个元素,我们会发现最后环里任意两点$gcd$为所有元素最大公约数以后不再变化。那么我们就知道对于环内每个点上的x会对环上所有点产生$F(gcd,x)$的贡献。这样我们用状态$H$来表示在$gcd$的剩余系下都有那些位置被标记过,即$H=\cup_x F(gcd,x)$。

part3:

  由于这是一个有向完全图,当我们缩点以后,会发现这还是一个有向完全图,不过这次是有向完全DAG。

  我们已经计算出了缩点后每个环点的状态。

  考虑在这个有向完全DAG的性质。

  1.点的出度是递减的。

  2.点的入度是递增的。

  3.根据拓扑序遍历我们会得到一条链,且链上点标号递减。

  以下为缩点后点数为5的例子(由于linux不太会用且校园网有限制只给出有向边,请读者手画一下……):

  5->4,5->3,5->2,5->1;4->3,4->2,4->1;3->2,3->1;2->1

  我们考虑此时环对环的贡献可以转化为$H$间的贡献,其贡献方式与点完全相同。由于缩点以后图的特殊性质,我们如果根据两点之间有边计算贡献无疑会T得飞起。以5对3的贡献为例,一种是5先给4贡献,4在计算此时$H_4$对3的贡献时再把5的贡献传给3,另一种是5对3直接计算贡献。显然我们发现这两种最后的结果都是一样的。那么前者无疑是跟为优秀的,我们按照拓扑后得到的链来传递贡献的话,那么就可以在只枚举一次每个环的计算出所有的贡献。

代码:

  

  1. #include "bits/stdc++.h"
  2.  
  3. using namespace std;
  4.  
  5. inline int read(){
  6. int s=,k=;char ch=getchar();
  7. while (ch<''|ch>'') ch=='-'?k=-:,ch=getchar();
  8. while (ch>&ch<='') s=s*+(ch^),ch=getchar();
  9. return s*k;
  10. }
  11.  
  12. const int N=5e3+,M=2e6+,mod=1e9+;
  13. typedef long long ll;
  14.  
  15. struct edges {
  16. int v;edges *last;
  17. }edge[N*N],*head[N<<],*ecnt=edge;
  18.  
  19. inline void push(int u,int v){
  20. *ecnt=(edges){v,head[u]},head[u]=ecnt++;
  21. }
  22.  
  23. inline int powmod(int a,int b){
  24. int ret=;
  25. while (b) {
  26. if(b&) ret=(ll)ret*a%mod;
  27. a=(ll)a*a%mod;
  28. b>>=;
  29. }return ret;
  30. }
  31.  
  32. inline int gcd(int x,int y){
  33. return y?gcd(y,x%y):x;
  34. }
  35.  
  36. int bcc_cnt,bccno[N],stk[N],dfn[N],low[N],idx,top,bgcd[N],s[N],n,a,b,instk[N];
  37.  
  38. inline void tarjan(int x) {
  39. low[x]=dfn[x]=++idx;
  40. stk[++top]=x;
  41. instk[x]=true;
  42. for (edges *i=head[x];i;i=i->last)
  43. if(!dfn[i->v])
  44. tarjan(i->v),low[x]=min(low[x],low[i->v]);
  45. else if(instk[i->v]) low[x]=min(low[x],dfn[i->v]);
  46. if(dfn[x]==low[x]) {
  47. bcc_cnt++;int t;
  48. do instk[t=stk[top--]]=false,bccno[t]=bcc_cnt,bgcd[bcc_cnt]=gcd(bgcd[bcc_cnt],s[t]);while (t!=x);
  49. }
  50. }
  51.  
  52. char me[N],gold[M<<];
  53. int fr[N<<],in[N],now[N],num[N],mx[N],mn[N];
  54.  
  55. int inv[N],fac[N];
  56.  
  57. #define C(i,j) ((ll)fac[(i)]*inv[(j)]%mod*inv[(i)-(j)]%mod)
  58.  
  59. int main(){
  60. //freopen("1.in","r",stdin);
  61. //freopen("war.out","w",stdout);
  62. n=read(),a=read(),b=read();
  63. for (int i=;i<=n;++i) {
  64. scanf("%s",me+);
  65. for (int j=;j<=n;++j) if(me[j]^) push(i,j);
  66. }
  67. for (int i=;i<=n;++i) {
  68. s[i]=read();
  69. fr[i]=fr[i-]+s[i-];
  70. scanf("%s",gold+fr[i]);
  71. }
  72. for (int i=;i<=n;++i) if(!dfn[i])
  73. tarjan(i);
  74. bgcd[]=s[n];
  75. for (int i=;i<=bcc_cnt;++i)
  76. fr[i+n]=fr[i-+n]+bgcd[i-];
  77. fr[n+bcc_cnt+]=fr[n+bcc_cnt]+bgcd[bcc_cnt];
  78. for (int i=;i<fr[n+];++i)
  79. gold[i]^=;
  80. for (int i=;i<=n;++i) {
  81. for (edges *j=head[i];j;j=j->last)
  82. if (bccno[i]!=bccno[j->v])
  83. push(bccno[i]+n,bccno[j->v]+n),++in[bccno[j->v]];
  84. for (int j=fr[i];j<fr[i+];++j)
  85. if (gold[j])
  86. gold[fr[bccno[i]+n]+(j-fr[i])%bgcd[bccno[i]]]=true;
  87. }
  88. now[bcc_cnt]=bgcd[bcc_cnt];
  89. for (int i=bcc_cnt;i>;--i) {
  90. now[i-]=gcd(bgcd[i],bgcd[i-]);
  91. for (int j=;j<bgcd[i];++j) if(gold[fr[i+n]+j])
  92. ++num[i],gold[fr[i+n-]+j%now[i-]]=true;
  93. }
  94. for (int j=;j<bgcd[];++j) if(gold[fr[+n]+j])
  95. ++num[];
  96. for (int i=;i<=n;++i) {
  97. mx[i]=(ll)num[bccno[i]]*s[i]/bgcd[bccno[i]];
  98. for (int j=fr[i];j<fr[i+];++j)
  99. mn[i]+=gold[j];
  100. }
  101. fac[]=;
  102. for (int i=;i<=n;++i) fac[i]=(ll)fac[i-]*i%mod;inv[]=inv[]=;
  103. for (int i=;i<=n;++i) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
  104. for (int i=;i<=n;++i) inv[i]=(ll)inv[i]*inv[i-]%mod;
  105. int ans=;
  106. for (int i=;i<=n;++i) {
  107. int c1=,c2=;
  108. for (int j=;j<=n;++j) if (mn[j]>mx[i]) ++c1;
  109. if (c1>=a) continue;
  110. for (int j=;j<=n;++j)
  111. if (mn[j]<=mx[i]&&(mx[j]>mx[i]||mx[j]==mx[i]&&j>i)) ++c2;
  112. for (int j=min(b-,min(c2,a--c1));b-j-<=c1&&(~j);--j)
  113. ans=(ans+C(c2,j)*C(c1,b-j-)%mod)%mod;
  114. }
  115. printf("%d\n",ans);
  116. }

[codeforces 804F. Fake bullions]的更多相关文章

  1. 【Codeforces】【图论】【数量】【哈密顿路径】Fake bullions (CodeForces - 804F)

    题意 有n个黑帮(gang),每个黑帮有siz[i]个人,黑帮与黑帮之间有有向边,并形成了一个竞赛完全图(即去除方向后正好为一个无向完全图).在很多年前,有一些人参与了一次大型抢劫,参与抢劫的人都获得 ...

  2. Solution -「CF 804F」Fake bullions

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点的竞赛图,第 \(i\) 个点代表了 \(s_i\) 个人,每个人(0-based)可能有真金条.此后在 ...

  3. Codeforces 802I Fake News (hard) (SA+单调栈) 或 SAM

    原文链接http://www.cnblogs.com/zhouzhendong/p/9026184.html 题目传送门 - Codeforces 802I 题意 求一个串中,所有本质不同子串的出现次 ...

  4. Codeforces 802I Fake News (hard)

    Codeforces 802I 题意:统计所有不同子串出现次数的平方的和. 想法:建一个SAM,$Ans=\sum (step[i]-step[fa[i]])*right[i]^2$ #include ...

  5. [CF804F]Fake bullions

    Solution: ​ 这题可以分为两个部分, ​ 一个部分为处理出每个点最大的金条数与最小的金条数,记为 \([Min_i, Max_i]\) ​ 第二部分为对于 \(n\) 个变量 \(x_i\i ...

  6. CodeForces 805A Fake NP

    直觉. 一段区间中,肯定是$2$的倍数最多,因为区间长度除以$2$得到的数字最大.但只有$1$个数字的时候需要特判. #include <cstdio> #include <cmat ...

  7. codeforces411div.2

    每日CF: 411div2 Solved A CodeForces 805A Fake NP Solved B CodeForces 805B 3-palindrome Solved C CodeFo ...

  8. Codeforces Round #310 (Div. 2) B. Case of Fake Numbers 水题

    B. Case of Fake Numbers Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/5 ...

  9. 构造 Codeforces Round #310 (Div. 2) B. Case of Fake Numbers

    题目传送门 /* 题意:n个数字转盘,刚开始每个转盘指向一个数字(0~n-1,逆时针排序),然后每一次转动,奇数的+1,偶数的-1,问多少次使第i个数字转盘指向i-1 构造:先求出使第1个指向0要多少 ...

随机推荐

  1. profile bashrc bash_profile之间的区别和联系

    profile bashrc bash_profile之间的区别和联系 博客分类: Linux   执行顺序为:/etc/profile -> (~/.bash_profile | ~/.bas ...

  2. jquery中利用队列依次执行动画

    如果有5个隐藏的div,要让它们依次显示,通常的做法是要一个一个嵌套在回调函数里面,这样导致代码看起来非常不直观. $("#div1").slideDown(1000,functi ...

  3. 使用mpvue开发微信小程序

    更多内容请查看 我的新博客 地址 : 前言 16年小程序刚出来的时候,就准备花点时间去学学.无奈现实中手上项目太多,一个接着一个,而且也没有开发小程序的需求,所以就一拖再拖. 直到上周,终于有一个小程 ...

  4. Partitions - Partition Storage Modes and Processing-MOLAP、ROLAP、HOLAP

    https://docs.microsoft.com/en-us/sql/analysis-services/multidimensional-models-olap-logical-cube-obj ...

  5. CSS样式渐变代码,兼容IE8

    background: -webkit-linear-gradient(top,#ffffff,#f5f5f5); background: -moz-linear-gradient(top,#ffff ...

  6. cocos2d-x_ Windows下Android环境搭建

    在Windows环境下编译cocos2d-x-3.0 Android-NDK编译:cocos2d-x(二) Mac 下搭建:http://www.cocoachina.com/bbs/read.php ...

  7. 13.git的简单使用

    安装 https://git-scm.com/downloads 一直点下一步就可以,安装完后打开方法:‘开始菜单’-->'Git'-->''Git Bash 安装完成后设置名字和电子邮件 ...

  8. rsync 密钥文件错误问题总结

    rsync 可以使用 --password-file 选项指定密钥文件,密钥文件中简单存放 rsync 密码:在第一次使用密钥文件的时候经常遇到文件权限相关问题:这里总结一下,我遇到的问题. 问题描述 ...

  9. Spring温故而知新 – Spring AOP

    AOP的相关专业术语 通知(Advice):定义在连接点做什么 Spring中通知类型:前置通知,后置通知,返回通知,异常通知,环绕通知 连接点(JoinPoint):程序执行过程中拦截的点,Spin ...

  10. ubuntu 命令整合2

    通配符 * 匹配任意多个字符 ?匹配一个任意字符 示例:ls *.txt  rm -rf *.txt 文本编辑器 vi.vim 格式:vi 文件名 编辑 vi的三种工作模式 正常模式(启动进入的模式) ...