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;
}