[洛谷题面]https://www.luogu.org/problemnew/show/P4221

首先考虑判定一个子图是否合法:

(1)连通:并查集判断即可。

(2)没有欧拉回路:存在欧拉回路的条件是度数均为偶数,计算度数判断即可。

容易想到进行状压DP,设 \(F[S]\) 表示选取点集 \(S\) 的答案。

\[F[S]=\frac{1}{SumW(S)} \sum_{T\subseteq S} F[S-T]*SumW(T)
\]

直接按上式暴力,复杂度为 \(O(3^n)\),可以通过 \(15pts\)。

然而注意到这是一个类似子集卷积的形式,显然是可以FWT优化的,而由于卷积式中有本身,故可以按照集合大小从小到大计算即可。

时间复杂度 \(O(n^22^n)\),实现时要注意寻址的连续否则容易被卡常。一个子集卷积85分

  1. #include<cstdio>
  2. typedef long long ll;
  3. const int N=22,M=1<<21,P=998244353;
  4. int fpow(int a,int b)
  5. {
  6. ll w(1),o(a);
  7. while(b) {
  8. if(b&1) w=w*o%P;
  9. o=o*o%P;
  10. b>>=1;
  11. }
  12. return w;
  13. }
  14. int Inv(int x)
  15. {
  16. return fpow(x,P-2);
  17. }
  18. int n,m,k,len,w[N],sum[M],sk[M],ski[M],mark[M],f[N],deg[N],dp[N][M],g[N][M];
  19. struct edge {
  20. int u,v;
  21. }e[N*N];
  22. inline int fp(int i,int j)
  23. {
  24. return (i>>(j-1))&1;
  25. }
  26. inline void upd(int&x, int y)
  27. {
  28. x=(x+y)%P;
  29. }
  30. int find(int x)
  31. {
  32. return f[x]==x?x:f[x]=find(f[x]);
  33. }
  34. int ck(int D)
  35. {
  36. int y=0;
  37. for(int i=1; i<=n; i++)
  38. if(fp(D,i))
  39. {
  40. int x=find(i);
  41. if(!y) y=x;
  42. if(x^y) return 1;
  43. }
  44. for(int i=1; i<=n; i++)
  45. if(fp(D,i))
  46. {
  47. if(deg[i]&1)
  48. return 1;
  49. }
  50. return 0;
  51. }
  52. inline void re(int &x) { x+=x>>31&P; }
  53. void fwt(int *s,int o)
  54. {
  55. for(int l=1; l<len; l<<=1)
  56. for(int i=0; i<len; i+=l<<1)
  57. for(int j=i; j<i+l; j++)
  58. if(!o) re(s[j+l]+=s[j]-P);
  59. else re(s[j+l]-=s[j]);
  60. }
  61. int main()
  62. {
  63. scanf("%d%d%d",&n,&m,&k);
  64. len=1<<n;
  65. for(int i=1; i<=m; i++)
  66. scanf("%d %d",&e[i].u,&e[i].v);
  67. for(int i=1; i<=n; i++)
  68. scanf("%d",&w[i]);
  69. for(int i=1; i<len; i++)
  70. {
  71. for(int j=1; j<=n; j++)
  72. if(fp(i,j))
  73. upd(sum[i],w[j]);
  74. sk[i]=fpow(sum[i],k);
  75. ski[i]=Inv(sk[i]);
  76. }
  77. for(int i=1; i<len; i++)
  78. {
  79. for(int j=1; j<=n; j++)
  80. if(fp(i,j)) f[j]=j,deg[j]=0;
  81. for(int j=1; j<=m; j++)
  82. if(fp(i,e[j].u) && fp(i,e[j].v))
  83. {
  84. deg[e[j].u]++;
  85. deg[e[j].v]++;
  86. int fu=find(e[j].u),fv=find(e[j].v);
  87. if(fu^fv) f[fu]=fv;
  88. }
  89. mark[i]=ck(i);
  90. }
  91. for(int i=1; i<len; i++)
  92. if(mark[i])
  93. g[__builtin_popcount(i)][i]=sk[i];
  94. for(int i=0; i<=n; i++) fwt(g[i],0);
  95. dp[0][0]=1;
  96. fwt(dp[0],0);
  97. for(int i=1; i<=n; i++)
  98. {
  99. for(int k=0; k<i; k++)
  100. for(int j=1; j<len; j++)
  101. re(dp[i][j]+=(ll)dp[k][j]*g[i-k][j]%P-P);
  102. fwt(dp[i],1);
  103. for(int j=1; j<len; j++)
  104. if(dp[i][j]) dp[i][j]=(ll)dp[i][j]*ski[j]%P;
  105. if(i==n)
  106. {
  107. printf("%d",dp[n][len-1]);
  108. break;
  109. }
  110. fwt(dp[i],0);
  111. }
  112. return 0;
  113. }

[WC2018]州区划分(状压,子集卷积)的更多相关文章

  1. UOJ348 WC2018 州区划分 状压DP、欧拉回路、子集卷积

    传送门 应该都会判欧拉回路吧(雾 考虑状压DP:设\(W_i\)表示集合\(i\)的点的权值和,\(route_i\)表示点集\(i\)的导出子图中是否存在欧拉回路,\(f_i\)表示前若干个城市包含 ...

  2. [WC2018]州区划分(状压DP+FWT/FMT)

    很裸的子集反演模板题,套上一些莫名其妙的外衣. 先预处理每个集合是否合法,再作显然的状压DP.然后发现可以写成子集反演的形式,直接套模板即可. 子集反演可以看这里. 子集反演的过程就是多设一维代表集合 ...

  3. UOJ #348 州区划分 —— 状压DP+子集卷积

    题目:http://uoj.ac/problem/348 一开始可以 3^n 子集DP,枚举一种状态的最后一个集合是什么来转移: 设 \( f[s] \) 表示 \( s \) 集合内的点都划分好了, ...

  4. 【UOJ348】【WC2018】州区划分 状压DP FWT

    题目大意 给定一个\(n\)个点的无向图,对于每种 \(n\) 个点的划分\(\{S_1,S_2,\ldots,S_k\}\),定义它是合法的,当且仅当每个点都在其中的一个集合中且对于任何的\(i\i ...

  5. [WC2018]州区划分(FWT,FST)

    [WC2018]州区划分(FWT,FST) Luogu loj 题解时间 经典FST. 在此之前似乎用到FST的题并不多? 首先预处理一个子集是不是欧拉回路很简单,判断是否连通且度数均为偶数即可. 考 ...

  6. [WC2018]州区划分

    [WC2018]州区划分 注意审题: 1.有序选择 2.若干个州 3.贡献是州满意度的乘积 枚举最后一个州是哪一个,合法时候贡献sum[s]^p,否则贡献0 存在欧拉回路:每个点都是偶度数,且图连通( ...

  7. [WC2018]州区划分——FWT+DP+FST

    题目链接: [WC2018]州区划分 题目大意:给n个点的一个无向图,点有点权,要求将这n个点划分成若干个部分,每部分合法当且仅当这部分中所有点之间的边不能构成欧拉回路.对于一种划分方案,第i个部分的 ...

  8. [UOJ#348][WC2018]州区划分

    [UOJ#348][WC2018]州区划分 试题描述 小 \(S\) 现在拥有 \(n\) 座城市,第ii座城市的人口为 \(w_i\),城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 ...

  9. Luogu4221 WC2018州区划分(状压dp+FWT)

    合法条件为所有划分出的子图均不存在欧拉回路或不连通,也即至少存在一个度数为奇数的点或不连通.显然可以对每个点集预处理是否合法,然后就不用管这个奇怪的条件了. 考虑状压dp.设f[S]为S集合所有划分方 ...

随机推荐

  1. my codestyle

    代码风格 缩进 缩进采用4个空格或tab. 原则是:如果地位相等,则不需要缩进:如果属于某一个代码的内部代码就需要缩进. 变量命名 变量命名遵守遵从驼峰命名法,统一使用lowerCamelCase风格 ...

  2. Redis06——Redis五大数据类型 list

    list 单键多值 Redis列表是简单的字符串列表,按照插入顺序排序,可以添加左边/右边 底层实际上是一个双向链表,对两端的操作性能好,但是通过索引下标的操作中间节点性能较差  lpush/rpus ...

  3. Linux05——用户操作

    用户操作 1.新增用户(useradd 新用户名): 2.设置密码(passwd 用户名): 3.用户是否存在(id  用户名): 4.切换用户(su - 切换用户名) **—— **       s ...

  4. opencv:形态学操作-开闭操作

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...

  5. 深度学习之tensorflow框架(中)

    会话 开启会话 tf.Session用于完整的程序中 tf.InteractiveSession用于交互式上下文中的tensorflow 查看张量的值 都必须在会话里面 c_new_value=new ...

  6. 主席树板子 p2104

    #include<cstdio> #include<algorithm> #include<vector> using namespace std; ; int n ...

  7. win10编译OPenBlas

    之前没有编译过OpenBlas,今天试了一下. 与参考博客不同之处,我的系统是win10,opencOpenBlas版本0.2.14,Visual Studio版本15. 编译使用MSYS2安装min ...

  8. C语言程序设计(三)——顺序程序设计

    目录: 常量.c 常量分类:   (1)字面常量(直接常量):数值常量(分为整型常量和浮点型常量).字符串常量和字符常量 (2)符号常量 (3)常变量 \f,换页,将当前位置移到下一页的开头 \v,垂 ...

  9. org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。

    org.apache.catalina.connector.ClientAbortException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接. at org ...

  10. Vue-路由跳转的几种方式和路由重定向

    一.标签路由 router-link 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始. 1.不传参 <router-link :to=& ...