abc246F typewriter (容斥原理)

题意: 给出n个串每个串都是abcdefghijklmnopqrstuvwxyz的一个子序列,每次可用一个串中的字母随意个来组成长度为l的串,求方案
思路:对于一个有m个字母串的方案是l个位置一个位置有m种选择,所以是m的l次方。 我们要算的答案:A1 U A2 U A3。要除去重复的部分,这显然就是容斥原理。把每个串的字母出现情况对应到二进制中可以方便的求交集。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long

#define PII pair<ll, ll>
const int N = 1e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI = acos(-1.0);
int s[20];
long long power(long long a,long long b){
  long long x=1,y=a;
  while(b>0){
    if(b&1ll){
      x=(x*y)%mod;
    }
    y=(y*y)%mod;
    b>>=1;
  }
  return x%mod;
}

int main() {
    int n, l; cin >> n >> l;
    for ( int i = 0; i < n; ++ i ) {
        string ss; cin >> ss;
        for (auto j : ss) {
            s[i] |= (1 << (j - 'a'));
        }
    }

    ll res = 0;
    //二进制枚举容斥原理的式子
    for ( int i = 1; i < (1 << n); ++ i ) { //注意从1开始
        int tmp = (1 << 26) - 1; int cnt = 0;
        //这是一个求交集的过程
        for ( int j = 0; j < n; ++ j ) {
            if(i & (1 << j)) tmp &= s[j], ++ cnt;
        }
        int pc = __builtin_popcount((unsigned int)tmp);
        
        if(cnt % 2) res = (res + power(pc, l)) % mod;
        else res = ((res - power(pc, l)) % mod + mod) % mod;
    }
     cout << res << '\n';
    return 0;
}
posted @ 2022-04-03 14:29  qingyanng  阅读(30)  评论(0编辑  收藏  举报