题目链接:http://wikioi.com/problem/1778/
分析:
我们先思考,当只有一个序列时,如何求出其有多少个不重复的子序列?显然可以定义F[I]表示这个序列的前I位有多少个不同的子序列,转移方程很简单,因为第I个字母可以接在某序列的后面,也可以不接,自然就是F[I]=F[I-1]*2。这样我们会发现答案就是2^长度。但是,这显然是错的。因为我们没有判重!
要知道如何去重,就必须知道出现重复序列的原因!
设当前位S[I]=’a’,并且存在一个最大的J,使得J
现在我们可以将问题扩展到复杂情况了,有类似的思想,可以轻易想到转移方程,当A[I]=B[J]=C[K]时,显然
F[I,J,K]=F[I-1,J-1,K-1]*2-F[II-1,JJ-1,KK-1],其中II、JJ、KK分别为三个序列在I、J、K位前的最靠近该位的位置,并且A[I]=A[II],B[J]=B[JJ],C[K]=C[KK]。貌似到此问题得到解决了,但是写程序的时候会发现,多序列和单序列还是有不同的!
多序列和单序列不同之处在于:多序列需要考虑字符不相等的时候的转移!必须将前面的状态全部转移过来,又不能重复,有什么思想可以解决??
容斥原理!!
所以可以得到状态转移方程:
F[I,J,K]=
F[I-1,J,K]+F[I,J-1,K]+F[I,J,K-1]
-F[I-1,J-1,K]-F[I-1,J,K-1]-F[I,J-1,K-1]
+F[I-1,J-1,K-1]。
特别提示:这样的做法包括空序列,显然由一个字符构成的序列时由空序列转移而来的,所以输出答案时需要减去这个空序列。另外,此题要用高精,压位。
代码:
#include
#include
#include
#include
#define ff 1000000000
using namespace std;
int n;
struct node
{
int s[10];
} f[151][151][151];
inline void jian( int i, int j, int k, int i1,int j1,int k1 )
{
for (int ji=1;ji<=9;ji++)
{
f[i][j][k].s[ji]-=f[i1][j1][k1].s[ji];
if (f[i][j][k].s[ji]<0)
{
f[i][j][k].s[ji+1]-=1;
f[i][j][k].s[ji]+=ff;
}
}
}
inline void jia( int i, int j, int k, int i1,int j1,int k1,int kk)
{
for (int ji=1;ji<=kk;ji++)
for (int ki=1;ki<=9;ki++)
{
f[i][j][k].s[ki]+=f[i1][j1][k1].s[ki];
if (f[i][j][k].s[ki]>=ff)
{
f[i][j][k].s[ki+1]+=(f[i][j][k].s[ki]/ff);
f[i][j][k].s[ki]%=ff;
}
}
}
int main()
{
string a=" ",b=" ",c=" ",aa,bb,cc;
int i,j,k;
cin>>n;
cin>>aa>>bb>>cc;
a+=aa;b+=bb;c+=cc;
for(i=0;i<=n;++i)
for(j=0;j<=n;++j)
{
f[0][i][j].s[1]=1;
f[i][j][0].s[1]=f[i][0][j].s[1]=f[0][i][j].s[1];
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
for (k=1;k<=n;k++)
{
if (a[i]==b[j]&&b[j]==c[k])
{
jia(i,j,k,i-1,j-1,k-1,2);
int ji=i-1; while (a[ji]!=a[i]&&ji>0) ji--;
int jj=j-1; while (b[jj]!=b[j]&&jj>0) jj--;
int jk=k-1; while (c[jk]!=c[k]&&jk>0) jk--;
if(ji>0&&jj>0&&jk>0) jian(i,j,k,ji-1,jj-1,jk-1);
}
else
{
jia(i,j,k,i-1,j,k,1);
jia(i,j,k,i,j-1,k,1);
jia(i,j,k,i,j,k-1,1);
jia(i,j,k,i-1,j-1,k-1,1);
jian(i,j,k,i-1,j-1,k);
jian(i,j,k,i,j-1,k-1);
jian(i,j,k,i-1,j,k-1);
}
}
jian(n,n,n,0,0,0);
int jiji=9; while (f[n][n][n].s[jiji]==0) jiji--;
cout<=1;i--) printf("%.9d",f[n][n][n].s[i]);
return 0;
}