zoukankan      html  css  js  c++  java
  • UOJ#348 州区划分

    解:有一个很显然的状压......

    就设f[s]表示选的点集为s的时候所有方案的权值和。

    于是有f[s] = f[s t] * (sum[t] / sum[s])P

    这枚举子集是3n的。

    然后发现这是子集卷积,参考资料

    于是就FWT搞一下...看代码

      1 #include <bits/stdc++.h>
      2 
      3 typedef long long LL;
      4 const int N = 30, M = 2100000, MO = 998244353;
      5 
      6 struct Edge {
      7     int v, u;
      8 }edge[N * N];
      9 
     10 int w[N], sum[M], cnt[M], n, P, lm, invsum[M], pw[M], in[N], fa[N];
     11 int f[N][M], g[N][M];
     12 bool vis[M];
     13 
     14 int find(int x) {
     15     if(x == fa[x]) return x;
     16     return fa[x] = find(fa[x]);
     17 }
     18 
     19 inline void out(int x) {
     20     for(int i = 0; i < n; i++) {
     21         printf("%d", (x >> i) & 1);
     22     }
     23     return;
     24 }
     25 
     26 inline void merge(int x, int y) {
     27     fa[find(x)] = find(y);
     28     return;
     29 }
     30 
     31 inline int qpow(int a, int b) {
     32     int ans = 1;
     33     while(b) {
     34         if(b & 1) ans = 1ll * ans * a % MO;
     35         a = 1ll * a * a % MO;
     36         b = b >> 1;
     37     }
     38     return ans;
     39 }
     40 
     41 inline int pow(int x) {
     42     return P ? (P == 1 ? x : 1ll * x * x % MO) : 1;
     43 }
     44 
     45 inline void FWT_or(int *a, int n, int f) {
     46     for(int len = 1; len < n; len <<= 1) {
     47         for(int i = 0; i < n; i += (len << 1)) {
     48             for(int j = 0; j < len; j++) {
     49                 (a[i + len + j] += f * a[i + j]) %= MO;
     50                 if(a[i + len + j] < 0) a[i + len + j] += MO;
     51             }
     52         }
     53     }
     54     return;
     55 }
     56 
     57 int main() {
     58     int m;
     59     scanf("%d%d%d", &n, &m, &P);
     60 
     61     for(int i = 1, x, y; i <= m; i++) {
     62         scanf("%d%d", &edge[i].v, &edge[i].u);
     63     }
     64     for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
     65     lm = (1 << n) - 1; /// lm = 1111111111(2)
     66     for(int i = 2; i <= lm; i++) pw[i] = pw[i >> 1] + 1;
     67     for(int s = 1; s <= lm; s++) {
     68         cnt[s] = cnt[s ^ (s & (-s))] + 1;
     69         vis[s] = 0;
     70         memset(in + 1, 0, n * sizeof(int));
     71         for(int i = 1; i <= n; i++) {
     72             fa[i] = i;
     73         }
     74         for(int i = 1; i <= m; i++) {
     75             if(((s >> (edge[i].v - 1)) & 1) && ((s >> (edge[i].u - 1)) & 1)) {
     76                 in[edge[i].v]++;
     77                 in[edge[i].u]++;
     78                 merge(edge[i].u, edge[i].v);
     79             }
     80         }
     81         bool nol = 0;
     82         int temp = 0;
     83         for(int i = 1; i <= n; i++) {
     84             if(in[i] & 1) {
     85                 vis[s] = 1;
     86             }
     87             if((s >> (i - 1)) & 1) {
     88                 (sum[s] += w[i]) %= MO;
     89                 if(!temp) {
     90                     temp = find(i);
     91                 }
     92                 else if(find(i) != temp) {
     93                     nol = 1;
     94                 }
     95             }
     96         }
     97         if(nol) vis[s] = 1;
     98         invsum[s] = qpow(sum[s], MO - 2);
     99         if(vis[s]) {
    100             g[cnt[s]][s] = pow(sum[s]);
    101         }
    102     }
    103 
    104     f[0][0] = 1;
    105     for(int i = 1; i <= n; i++) {
    106         FWT_or(g[i], lm + 1, 1);
    107     }
    108     FWT_or(f[0], lm + 1, 1);
    109     for(int i = 1; i <= n; i++) {
    110         for(int j = 1; j <= i; j++) {
    111             for(int s = 0; s <= lm; s++) {
    112                 (f[i][s] += 1ll * f[i - j][s] * g[j][s] % MO) %= MO;
    113             }
    114         }
    115         FWT_or(f[i], lm + 1, -1);
    116         for(int s = 0; s <= lm; s++) {
    117             f[i][s] = 1ll * f[i][s] * pow(invsum[s]) % MO;
    118         }
    119         if(i < n) FWT_or(f[i], lm + 1, 1);
    120     }
    121     printf("%d
    ", f[n][lm]);
    122     return 0;
    123 }
    AC代码
  • 相关阅读:
    react ts axios 配置跨域
    npm run eject“Remove untracked files, stash or commit any changes, and try again.”错误
    java 进程的参数和list的线程安全
    帆软报表 大屏列表跑马灯效果JS
    帆软报表 快速复用数据集,避免重复劳动
    分析云 OA中部门分级思路和实现方法
    分析云 分段器 只显示一个块的数据
    分析云 更改服务默认的端口号
    分析云U8项目配置方法新版本(2)
    Oracle 创建时间维度表并更新是否工作日字段
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10721352.html
Copyright © 2011-2022 走看看