uoj#214. 【UNR #1】合唱队形

min-max 容斥 (m)大了直接爆搜 (m)小的话就状压DP
先开小数组 dp两维开数组时还弄反了...

#include<bits/stdc++.h>
using namespace std;
#define fp(i,l,r) for(register int (i)=(l);i<=(r);++(i))
#define fd(i,l,r) for(register int (i)=(l);i>=(r);--(i))
#define fe(i,u) for(register int (i)=front[(u)];(i);(i)=e[(i)].next)
#define mem(a) memset((a),0,sizeof (a))
#define O(x) cerr<<#x<<':'<<x<<endl
#define int long long
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x*f;
}
void wr(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>=10)wr(x/10);
	putchar('0'+x%10);
}
const int mod=998244353;
inline void tmod(int &x){x%=mod;}
inline void rmod(int &x){x+=x>>31&mod;}
inline int qpow(int a,int b){
	int res=1;a%=mod;
	for(;b;b>>=1,tmod(a*=a))
		if(b&1)tmod(res*=a);
	return res;
}
inline int ginv(int x){return qpow(x,mod-2);}
bool book[35][35],Can[35];
int n,m,dp[2][1<<10][910],a[1<<11],tot,g[1001],ans,buc[33][33];
char str[35];
void dfs(int d,int st,bool sgn){
	if(!d){
		if(sgn)rmod(ans-=g[st]);else rmod(ans+=g[st]-mod);
		return;
	}
	dfs(d-1,st,sgn);
	if(Can[d]){
		fp(i,1,m)if(!buc[d+i-1][str[i]]++)++st;
		dfs(d-1,st,!sgn);
		fp(i,1,m)if(!--buc[d+i-1][str[i]])--st;
	}
}
inline void solve1(){
	dfs(n-m+1,0,1);
	printf("%lld
",ans*tot%mod);
}
inline void solve2(){
	int S=(1<<m)-1,cur=0;
	fp(i,1,m)a[1<<i-1]=1<<str[i];
	fp(i,1,S)a[i]=a[i^(i&-i)]|(a[i&-i]);
	fp(i,1,S)a[i]=__builtin_popcount(a[i]);S>>=1;
	mem(dp[0]);dp[0][0][0]=mod-1;
	fp(i,1,n){
		cur^=1;mem(dp[cur]);
		fp(j,0,S)
			fp(k,0,tot)if(dp[cur^1][j][k]){
			const int t=j<<1,p=dp[cur^1][j][k];
			rmod(dp[cur][t&S][k+a[t]]+=p-mod);
			if(Can[i])rmod(dp[cur][(t|1)&S][k+a[t|1]]-=p);
		}
	}
	fp(i,0,S)fp(j,0,tot)
		tmod(ans+=g[j]*dp[cur][i][j]);
	printf("%lld
",ans*tot%mod);
}
inline void solve(){
	mem(book);mem(Can);mem(a);tot=ans=0;
	n=read();m=read();
	fp(i,1,n){
		scanf("%s",str+1);int tt=strlen(str+1);tot+=tt;
		fp(j,1,tt)book[i][str[j]-'a']=1;
	}
	scanf("%s",str+1);fp(i,1,m)str[i]-='a';
	bool fl=0;
	fp(i,1,n-m+1){
		fp(j,1,m)if(!book[i+j-1][str[j]])goto ss;
		Can[i]=1;fl=1;
	    ss:;
	}
	if(!fl){puts("-1");return;}
	if(m<=11)solve2();
	else solve1();
}
main(){
	fp(i,1,1000)rmod(g[i]=ginv(i)+g[i-1]-mod);
	int tt=read();
	while(tt--)solve();
	return 0;
}
原文地址:https://www.cnblogs.com/WinterSpell/p/13272242.html