BZOJ1566: [NOI2009]管道取珠

题目描述: 传送门

题解:

这题要求的是ai^2,我们难以直接写DP硬求,此时就要思考一些奇伎淫巧了。
我们注意到,ai^2就是ai*ai,如果我们同时进行两场游戏,两边相同时相加,最后不就是ai^2了吗?
所以我们可以定义f[i][j][k][t] 表示第一局第一个管取到第i个,第二个管取到第j个;第二局第一个管取到第k个,第二个管取到第t个。但是这样还会超时。我们注意到i+j等于k+t,那么我们就可以省去t这一维,表示为f[i][j][k]了。

代码如下:

#include<cstdio>
#include<string>
using namespace std;
const int maxn=505,tt=1024523;
int n,m,len1,len2,a[maxn],b[maxn],f[maxn][maxn][maxn];
int main(){
    scanf("%d %d",&n,&m);
    char ch=getchar();
    while (ch!='A'&&ch!='B') ch=getchar();
    while (ch=='A'||ch=='B') a[++len1]=ch-'A'+1,ch=getchar();
    ch=getchar();
    while (ch!='A'&&ch!='B') ch=getchar();
    while (ch=='A'||ch=='B') b[++len2]=ch-'A'+1,ch=getchar();
    f[0][0][0]=1;
    for (int i=0;i<=n;i++)
    for (int j=0;j<=m;j++)
    for (int k=0;k<=min(i+j,n);k++){
        int t=i+j-k;
        if (i&&k&&a[i]==a[k]) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1])%tt;
        if (i&&t&&a[i]==b[t]) f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%tt;
        if (j&&k&&b[j]==a[k]) f[i][j][k]=(f[i][j][k]+f[i][j-1][k-1])%tt;
        if (j&&t&&b[j]==b[t]) f[i][j][k]=(f[i][j][k]+f[i][j-1][k])%tt;
    }
    printf("%d\n",f[n][m][n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dyt_b/article/details/79980573