[关闭]
@xiaoziyao 2021-01-16T05:49:53.000000Z 字数 3639 阅读 897

AT2143 [ARC062D] AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer解题报告

解题报告


AT2143 [ARC062D] AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer解题报告:

更好的阅读体验

题意

分析

比较好玩的一道题。

首先,我们可以利用一种神奇的边双联通分量求法(注意,这里求的边双联通分量是指不存在割点的连通分量)把整个图分成若干个边集,然后分类讨论:

  1. void tarjan(int x,int last){
  2. dfn[x]=low[x]=++cnt;
  3. for(int i=start[x];i;i=then[i]){
  4. int y=to[i];
  5. if(y==last)
  6. continue;
  7. if(dfn[y]==0){
  8. stk[++top][0]=x,stk[top][1]=y;
  9. tarjan(y,x);
  10. low[x]=min(low[x],low[y]);
  11. if(dfn[x]<=low[y]){
  12. int a=0,b=0;
  13. tot++;
  14. while(a!=x||b!=y){
  15. a=stk[top][0],b=stk[top][1],top--;
  16. sumg[tot]++,sump[tot]+=(bel[a]!=tot)+(bel[b]!=tot);
  17. bel[a]=bel[b]=tot;
  18. }
  19. }
  20. }
  21. else if(dfn[y]<dfn[x]){
  22. stk[++top][0]=x,stk[top][1]=y;
  23. low[x]=min(low[x],dfn[y]);
  24. }
  25. }
  26. }


时间复杂度:

当然,如果你跟我一样无聊的话,可以把上面的式子化一下:,然后直接累乘做到

注意要带上,否则答案会多算一部分贡献(我就因为这调了半个小时)。

时间复杂度:

代码

  1. #include<stdio.h>
  2. const int maxn=1005,mod=1000000007,maxx=1000;
  3. int n,m,k,e,cnt,top,tot,prms,ans;
  4. int start[maxn],from[maxn],to[maxn],then[maxn],dfn[maxn],low[maxn],stk[maxn][2],deg[maxn],sump[maxn],sumg[maxn],bel[maxn];
  5. int phi[maxn],a[maxn],p[maxn],fac[maxn],nfac[maxn];
  6. inline int min(int a,int b){
  7. return a<b? a:b;
  8. }
  9. inline void add(int x,int y){
  10. then[++e]=start[x],start[x]=e,from[e]=x,to[e]=y;
  11. }
  12. void tarjan(int x,int last){
  13. dfn[x]=low[x]=++cnt;
  14. for(int i=start[x];i;i=then[i]){
  15. int y=to[i];
  16. if(y==last)
  17. continue;
  18. if(dfn[y]==0){
  19. stk[++top][0]=x,stk[top][1]=y;
  20. tarjan(y,x);
  21. low[x]=min(low[x],low[y]);
  22. if(dfn[x]<=low[y]){
  23. int a=0,b=0;
  24. tot++;
  25. while(a!=x||b!=y){
  26. a=stk[top][0],b=stk[top][1],top--;
  27. sumg[tot]++,sump[tot]+=(bel[a]!=tot)+(bel[b]!=tot);
  28. bel[a]=bel[b]=tot;
  29. }
  30. }
  31. }
  32. else if(dfn[y]<dfn[x]){
  33. stk[++top][0]=x,stk[top][1]=y;
  34. low[x]=min(low[x],dfn[y]);
  35. }
  36. }
  37. }
  38. void sieve(int k){
  39. p[1]=phi[1]=1;
  40. for(int i=2;i<=k;i++){
  41. if(p[i]==0)
  42. a[++prms]=i,phi[i]=i-1;
  43. for(int j=1;j<=prms;j++){
  44. if(i*a[j]>k)
  45. break;
  46. p[i*a[j]]=1;
  47. if(i%a[j]==0){
  48. phi[i*a[j]]=phi[i]*a[j];
  49. break;
  50. }
  51. phi[i*a[j]]=phi[i]*(a[j]-1);
  52. }
  53. }
  54. }
  55. int ksm(int a,int b){
  56. int res=1;
  57. while(b){
  58. if(b&1)
  59. res=1ll*res*a%mod;
  60. a=1ll*a*a%mod,b>>=1;
  61. }
  62. return res;
  63. }
  64. int calc(int n){
  65. int res=0,mul=1;
  66. for(int i=1;i<=n;i++){
  67. mul=1ll*mul*k%mod;
  68. if(n%i==0)
  69. res=(res+1ll*mul*phi[n/i]%mod)%mod;
  70. }
  71. return 1ll*res*ksm(n,mod-2)%mod;
  72. }
  73. inline int c(int n,int m){
  74. return n<m? 0:1ll*fac[n]*nfac[m]%mod*nfac[n-m]%mod;
  75. }
  76. int main(){
  77. scanf("%d%d%d",&n,&m,&k);
  78. sieve(maxx);
  79. fac[0]=1;
  80. for(int i=1;i<=maxx;i++)
  81. fac[i]=1ll*fac[i-1]*i%mod;
  82. nfac[maxx]=ksm(fac[maxx],mod-2);
  83. for(int i=maxx;i>=1;i--)
  84. nfac[i-1]=1ll*nfac[i]*i%mod;
  85. for(int i=1;i<=m;i++){
  86. int x,y;
  87. scanf("%d%d",&x,&y);
  88. add(x,y),add(y,x);
  89. }
  90. for(int i=1;i<=n;i++)
  91. if(dfn[i]==0){
  92. top=0;
  93. tarjan(i,0);
  94. }
  95. ans=1;
  96. for(int i=1;i<=tot;i++){
  97. if(sump[i]==1)
  98. ans=1ll*ans*k%mod;
  99. else if(sump[i]==sumg[i])
  100. ans=1ll*ans*calc(sump[i])%mod;
  101. else ans=1ll*ans*c(sumg[i]+k-1,sumg[i])%mod;
  102. }
  103. printf("%d\n",ans);
  104. return 0;
  105. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注