BZOJ2560:串珠子 状压dp
Mar 04, 2015 01:51:21 PM
思路:
令\(f[S]\)表示集合S形成连通图的方案数,\(g[s]\)表示集合S内部任意连边的方案数.
显然:
\[g[S]=\prod_{i,j\in{S},i<j}c_{i,j}+1\]
这个我们可以在\(O(2^n{n^2})\)的复杂度内算出来.
接下来考虑计算\(f[S]\).
我们用总数减去不连通的图的个数.
假设\(x\in{S}\),我们不妨枚举所有\(S\)的真子集\(S'\),其中\(S'\)就代表包含\(x\)的一个连通块,\(S-S'\)均与\(x\)不连通.
那么\(f[S']\)我们已经算过了,剩下的\(S-S'\)就利用我们之前预处理的随意连边的\(g\)数组.
于是我们得到转移:
\[f[S]=\sum_{S'\subset{S},x\in{S'}}f[S']g[S-S']\]
这个过程是\(O(3^n)\).
然后我们就在\(O(2^n{n^2}+3^n)\)的时间内解决了这题.
#include<cstdio> #include<cstring> #include<cctype> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; #define N 16 int f[1<<N],g[1<<N],h[1<<N],c[N][N]; static const int mod=(1e9)+7; inline void inc(int&x,int y){if((x+=y)>=mod)x-=mod;} #define p(S,x) (((S)>>(x))&1) int main(){ int n;scanf("%d",&n);register int i,j,k; for(i=0;i<n;++i)for(j=0;j<n;++j)scanf("%d",&c[i][j]); for(i=0;i<n;++i)f[1<<i]=g[1<<i]=1; for(i=1;i<(1<<n);++i)h[i]=h[i^(i&-i)]+1; for(i=1;i<(1<<n);++i){ if(h[i]==1)continue; else{ g[i]=1; for(j=0;j<n;++j)for(k=j+1;k<n;++k)if(p(i,j)&&p(i,k)) g[i]=(LL)g[i]*(c[j][k]+1)%mod; int ins; for(j=0;j<n;++j)if(p(i,j)){ins=j;break;} for(int mas=(i-1)&i;mas;mas=(mas-1)&i)if(p(mas,ins)) inc(f[i],(LL)f[mas]*g[i^mas]%mod); f[i]=(g[i]>=f[i])?g[i]-f[i]:g[i]+mod-f[i]; } } printf("%d",f[(1<<n)-1]); return 0; }
BZOJ1195:[HNOI2006]最短母串 AC自动机+状压dp
Jan 16, 2015 10:14:04 AM
思路:
首先我的思路十分傻叉,是\(f[i][j][k]\)表示长度为\(i\),在自动机上的节点为\(j\),包含子串的状态为\(k\)可不可能.但这样复杂度直接爆炸.
但是我们可以令\(f[i][j]\)表示在自动机上的节点为\(i\),包含子串的状态为\(j\)时的最短长度.
这样我们就转化成了边权均为1的单源最短路,BFS就行了.
若按照字母字典序从小到大的顺序进行BFS,得出的就是字典序最小的答案了.
(有点卡内存)
(话说我一开始AC自动机都写错,没治了)
#include<cstdio> #include<cstring> #include<cctype> #include<iostream> #include<algorithm> using namespace std; #define N 12 #define L 610 short ch[L][26],end[L],pre[L],cnt; char s[L]; int q[L],fr,ta; short lastchar[L*(1<<N)]; int laststate[L*(1<<N)]; short state[L*(1<<N)]; short ins[L*(1<<N)]; bool vis[L][1<<N]; char ans[L];int id; int main(){ int n;scanf("%d",&n);register int i,j; int p,y; for(i=1;i<=n;++i){ scanf("%s",s);int len=strlen(s); for(p=j=0;j<len;++j){ if(!ch[p][y=s[j]-'A'])ch[p][y]=++cnt;p=ch[p][y]; }end[p]|=1<<(i-1); } for(j=0;j<26;++j)if(ch[0][j])q[ta++]=ch[0][j]; int u,v,r; while(fr^ta){ u=q[fr++]; for(j=0;j<26;++j)if(ch[u][j]){ for(q[ta++]=v=ch[u][j],r=pre[u];r&&!ch[r][j];r=pre[r]);end[v]|=end[pre[v]=ch[r][j]]; } else ch[u][j]=ch[pre[u]][j]; } int mask; for(fr=ta=0,state[0]=ins[0]=0,++ta;fr^ta;){ u=ins[fr],mask=state[fr]; if(mask==(1<<n)-1){ for(;fr;fr=laststate[fr])ans[++id]=lastchar[fr]; for(i=id;i>=1;--i)putchar('A'+ans[i]); return 0; } for(j=0;j<26;++j)if(!vis[ch[u][j]][mask|end[ch[u][j]]]){ lastchar[ta]=j,laststate[ta]=fr,ins[ta]=ch[u][j],state[ta]=mask|end[ch[u][j]]; vis[ins[ta]][state[ta]]=1; ta++; }++fr; } return 0; }