[bzoj1566][NOI2009]管道取珠

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

n<=500

 

神题......

发现这个平方可以看作两个序列相同的对数  然后就可以表示状态了。

f[i][j][k]表示两个序列各选了i个,第1个序列在第一行选了j个,第二个序列在第二行选了k个,他们相同的方案数

转移比较简单,枚举两个序列各填哪一位即可。

复杂度n^3

复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 500
#define mod 1024523
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}
int f[2][505][505],n,m;
char A[MN+5],B[MN+5];
inline void R(int&x,int y){x+=y;x>=mod?x-=mod:0;}
int main()
{
    n=read();m=read();
    scanf("%s",A+1);scanf("%s",B+1);
    f[0][0][0]=1;
    for(int i=0,now=1,pre=0;i<n+m;++i)
    {
        for(int j=0;j<=min(i,n);++j)
            for(int k=0;k<=min(i,n);++k)
            {
                int J=i-j,K=i-k;
                if(j<n&&k<n&&A[j+1]==A[k+1]) R(f[now][j+1][k+1],f[pre][j][k]);
                if(j<n&&K<m&&A[j+1]==B[K+1]) R(f[now][j+1][k],f[pre][j][k]);
                if(J<m&&k<n&&B[J+1]==A[k+1]) R(f[now][j][k+1],f[pre][j][k]);
                if(J<m&&K<m&&B[J+1]==B[K+1]) R(f[now][j][k],f[pre][j][k]); 
            }     
        swap(now,pre);
        memset(f[now],0,sizeof(f[now])); 
    }
    printf("%d\n",f[(n+m)&1][n][n]);
    return 0;
}
复制代码

 

posted @ 2017-07-04 16:05  FallDream  阅读(227)  评论(0)    收藏  举报
编辑推荐:
· 糊涂啊!这个需求居然没想到用时间轮来解决
· 浅谈为什么我讨厌分布式事务
· 在 .NET 中使用内存映射文件构建高性能的进程间通信队列
· 一个 java 空指针异常的解决过程
· 揭开 SQL Server 和 PostgreSQL 填充因子的神秘面纱
阅读排行:
· 从硬盘爆满到 GitHub 封号,一位前端开发者的开源历险记
· 微软又一自动化开源王炸,Selenium 慌了!
· 微服务的10大问题
· 性能优化:两条SQL索引优化,CPU占用率从40%降至25%
· C#解析JSON数据全攻略
点击右上角即可分享
微信分享提示