题意:
就是给你n个键盘,每个键盘可以打一些字母,然后让你用键盘打出长度为m的字母的方案数有多少种。
思考:
刚开始我以为是每次只能用一个键盘,实际上可以随便用。但是很明显有k个字母的方案数就是k的m次方,但是怎么去重呢。其实根据去重原理,最简单的是3个键盘,1+2+3-12-13-23+123。然后递推一下就是对于一个多重集合去重的就是二进制枚举用了几个键盘,对于奇数加还是偶数加,就看看你到底是干什么,这个题首先是没有方案,拿过来键盘后才有方案,所以1个键盘的时候加,2个键盘的时候减…。所以如果是奇数个就加上方案数,如果是偶数个就减去方案数。 对了对于求方案的时候,是这些键盘共有的字母的方案数,因为如果不共有,比如两个键盘都有字母a,我现在又拿一个键盘,但是没有字母a,这时候对字母a就不要再去重了,因为他没有字母a。
之前就做过这种容斥类型的:无关。一定要对n可以2进制枚举范围的有敏感。
代码:
int T,n,m,k;
int va[N];
int ksm(int a,int b)
{
int sum = 1;
while(b)
{
if(b&1) sum = sum*a%mod;
a = a*a%mod;
b >>= 1;
}
return sum;
}
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
for(auto t:s) va[i] |= 1ll<<(t-'a');
}
int ans = 0;
for(int i=1;i<(1ll<<n);i++)
{
int now = (1ll<<26)-1,cnt = 0,res = 0;
for(int j=0;j<n;j++)
{
if(i>>j&1)
{
cnt++;
now &= va[j+1];
}
}
for(int j=0;j<26;j++) if(now>>j&1) res++;
if(cnt%2) ans = (ans+ksm(res,m))%mod;
else ans = (ans-ksm(res,m))%mod;
}
ans = (ans%mod+mod)%mod;
cout<<ans;
return 0;
}
总结:
多多思考积累经验。