65 lines
2.0 KiB
C++
65 lines
2.0 KiB
C++
/*
|
||
统计方案的时候,我们只考虑字符串的内容。不同来源生成的同样的字符串只算一种方案。所以重点思考字符的来源。
|
||
以n=3n=3为例,可以打印出的长度为L的字符串总数=(使用第1行的字符集打印出的字符串总数+使用第2行的字符集打印出的字符串总数+使用第3行的字符集打印出的字符串总数)-(使用第1行或第2行的字符集打印出的字符串总数+使用第2行或第3行的字符集打印出的字符串总数+使用第1行或第3行的字符集打印出的字符串总数)+(使用第1行或第2行或第3行的字符集打印出的字符串总数)=(使用第1行的字符集打印出的字符串总数+使用第2行的字符集打印出的字符串总数+使用第3行的字符集打印出的字符串总数)?(使用第1行或第2行的字符集打印出的字符串总数+使用第2行或第3行的字符集打印出的字符串总数+使用第1行或第3行的字符集打印出的字符串总数)+(使用第1行或第2行或第3行的字符集打印出的字符串总数)。
|
||
由于nn不超过1818,可以用00到2^{18}-12
|
||
18
|
||
?1表示每一行取或不取的可能性。从00到2^{18}-12
|
||
18
|
||
?1枚举i,如果ii包含奇数个11,说明该组合在容斥原理中要“加上”;如果ii包含偶数个11,说明该组合在容斥原理中要“减去”。
|
||
设i包含kk个11,我们还要快速求出这kk个字符集的交集。因为字符集最多2626个字母,而int有3232位,因此用3232位整数作为位示图,其中低2626位对应2626个字母出现或不出现即可。*/
|
||
#include <bits/stdc++.h>
|
||
using namespace std;
|
||
typedef long long ll;
|
||
typedef pair<int, int> pii;
|
||
const int maxn = 18;
|
||
const int mod = 998244353;
|
||
int n, L, mask[18];
|
||
char s[18][27];
|
||
ll ans;
|
||
ll qpow(ll a, ll b)
|
||
{
|
||
ll re = 1;
|
||
while (b != 0)
|
||
{
|
||
if ((b & 1) == 1)
|
||
re = re * a % mod;
|
||
a = a * a % mod;
|
||
b >>= 1;
|
||
}
|
||
return re;
|
||
}
|
||
int Count(int x)
|
||
{
|
||
int cnt = 0;
|
||
while (x != 0)
|
||
{
|
||
if ((x & 1) == 1)
|
||
cnt++;
|
||
x >>= 1;
|
||
}
|
||
return cnt;
|
||
}
|
||
int main()
|
||
{
|
||
scanf("%d%d", &n, &L);
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
scanf("%s", s[i]);
|
||
for (int j = 0; s[i][j] != '\0'; j++)
|
||
mask[i] |= (1 << (s[i][j] - 'a'));
|
||
}
|
||
for (int i = 1; i < (1 << n); i++)
|
||
{
|
||
int ch = (1 << 26) - 1, cnt = 0;
|
||
for (int j = 0; j < n; j++)
|
||
if (((1 << j)&i) != 0)
|
||
cnt++, ch &= mask[j];
|
||
if ((cnt & 1) == 1)
|
||
ans = (ans + qpow(Count(ch), L)) % mod;
|
||
else
|
||
ans = (ans + (mod - qpow(Count(ch), L)) % mod) % mod;
|
||
}
|
||
printf("%lld\n", ans);
|
||
return 0;
|
||
}
|