zoukankan      html  css  js  c++  java
  • [SOS DP][容斥] Codeforces 1620G Subsequences Galore

    题目大意

    给定一个字符串序列 \([t_1,t_2,\cdots ,t_m]\) ,定义 \(f([t_1,t_2,\cdots,t_m])\) 为至少是其中一个字符串 \(t_i\) 的子序列的字符串个数,其中 \(f([])=0\)

    给定一个字符串序列 \([s_1,s_2,\cdots ,s_m]\),对每一个子集 \([s_{i_1}, s_{i_2}, \cdots, s_{i_k}]\) 求出 \(f({[s_{i_1}, s_{i_2}, \cdots, s_{i_k}]})\)\(998244353\) 取模后的值。

    输出 \(f({[s_{i_1}, s_{i_2}, \cdots, s_{i_k}]})\times k\times (i_1+i_2+\cdots+i_k)\) 的异或和(不取模)。

    注意每个字符串 \(s_i\)​ 中的字母都是排好序的。

    题解

    设字符串 \(s\) 中字符 \(c\) 的个数为 \(\mathrm{cnt}(c)\),则该字符串的子序列的个数为 \(\prod_{c='a'}^{'z'}(\mathrm{cnt}(c)+1)\)

    对于同时是多个字符串的子序列的字符串的个数,只要对每个字符 \(c\)\(\mathrm{cnt}(c)\)\(\min\)\(1\) 再相乘即可。

    接下来考虑容斥。设字符串集为 \(S\),设同时是 \(S\) 中所有字符串的子序列的字符串的个数为 \(g(S)\),则有

    \[f(S)=\sum_{T\subseteq S} (-1)^{|T|-1} g(T) \]

    这个式子实际上是一个符号和奇偶校验码有关的子集和,直接用SOS DP或者说类似于FMT的方法直接算即可,时间复杂度 \(O(|\Sigma|n2^n)\)\(|\Sigma|\) 是字符集大小,本题中是 \(26\)

    \(x\) 的奇偶校验码可以用 __builtin_parity(x) 直接算,若 \(x\) 的二进制中有偶数个 \(1\),则返回 \(0\),否则返回 \(1\)

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define LL long long
    const LL MOD = 998244353;
    char buf[20010];
    int f[1 << 23], a[26];
    vector<int> v[25];
    int n;
    
    int main() {
        scanf("%d", &n);
        for (int i = 0;i < n;++i) {
            scanf("%s", buf + 1);
            v[i].resize(26);
            for (int j = 1;buf[j];++j)
                ++v[i][buf[j] - 'a'];
        }
        for (int i = 1;i < (1 << n);++i) {
            memset(a, 0x3f, sizeof(a));
            for (int j = 0;j < n;++j) {
                if (!(i & (1 << j))) continue;
                for (int k = 0;k < 26;++k)
                    a[k] = min(a[k], v[j][k]);
            }
            f[i] = 1;
            for (int k = 0;k < 26;++k)
                f[i] = 1LL * f[i] * (a[k] + 1) % MOD;
        }
        for (int i = 0;i < n;++i) {
            for (int j = 0;j < (1 << n);++j) {
                int x = __builtin_parity(j);
                if (j & (1 << i)) {
                    f[j] = (f[j] + -1 * f[j ^ (1 << i)]) % MOD;
                    if (f[j] < 0) f[j] += MOD;
                }
            }
        }
        LL ans = 0;
        for (int i = 0;i < (1 << n);++i) {
            if (!__builtin_parity(i)) f[i] = MOD - f[i];
            int k = 0, x = 0;
            for (int j = 0;j < n;++j)
                if (i & (1 << j)) { ++k; x += j + 1; }
            LL temp = 1LL * k * x * f[i];
            ans ^= temp;
        }
        printf("%I64d\n", ans);
    
        return 0;
    }
    
  • 相关阅读:
    Android_Spinner_example
    23.pyspider安装
    22.Windows及linux下gerapy使用
    21.scrapy爬虫部署
    12.利用kakatips对网站数据信息监控
    11.启信宝数据二次筛选解密(字符串的分割与拼接及正则匹配)-2
    10.Ubuntu操作系统及python2.7、3.5 exe
    9.数据库多表一起查询
    8.代理ip使用
    7.阿布云代理服务器试用
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15785863.html
Copyright © 2011-2022 走看看