[BZOJ1566][NOI2009]管道取珠

一道有点考思维的DP


抛一个题目连接BZOJ1566管道取珠
这题·······可能会想到数论,发现求不出来于是想DP。


分析:

设操作方案为k,现有一种输出方案,操作数为ai,令q=ai;
那么对应的操作方案为,k1,k2,k3·········k(q-1),kq
那么操作数的平方就相当于是
k1,k2,k3·········k(q-1),kq

k1,k2,k3·········k(q-1),kq
第一行的a(1~n)与下面a(1~n)都一一对应一次。

这个题就变成了:现在有两个人甲,乙在玩游戏,求两个人输出方案一样的次数之和。


代码

三位的DP数组,DP[输出管道球数(等价于取球次数)][甲在上管道取的次数][乙在上管道取的次数]
开滚动就可以过
BZOJ评测结果: Accepted 2800 kb 2800 ms
ps:主函数里乱糟糟一坨读入me写了好久,后来发现只要两个scanf(“%s”,a)就可以了······

#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

const int mmod=1024523;
int N,M,DP[2][503][503],t=0,tot;
bool A[505],B[505];

void solve(){
    register int i,j,k;
    int li;
    DP[0][0][0]=1;
    for(i=0;i<=tot-1;i++){//注意for循环里只能从0开始N+M-1结束,因为这是由前一个状态推后一个状态,下面同理
        t^=1;
        li=min(N,i);
        for(j=0;j<=li;j++){
            for(k=0;k<=li;k++){
                if(!DP[t^1][j][k])  continue;
                if(!(A[j+1]^A[k+1]))   (DP[t][j+1][k+1]+=DP[t^1][j][k])%=mmod;
                if(!(A[j+1]^B[i-k+1]))   (DP[t][j+1][k]+=DP[t^1][j][k])%=mmod;
                if(!(B[i-j+1]^A[k+1]))   (DP[t][j][k+1]+=DP[t^1][j][k])%=mmod;
                if(!(B[i-j+1]^B[i-k+1]))   (DP[t][j][k]+=DP[t^1][j][k])%=mmod;
            }
        }
        memset(DP[1^t],0,sizeof(DP[1^t]));
    }
    printf("%d",DP[t][N][N]%mmod);
}

int main(){
    char t=0;
    scanf("%d%d",&N,&M);
    tot=N+M;
    register int i;
    while(t!='A'&&t!='B')   t=getchar();
    for(i=1;i<=N;i++){
        if(t=='A')  A[N-i+1]=true;
        t=getchar();
    }
    while(t!='A'&&t!='B')   t=getchar();
    for(i=1;i<=M;i++){
        if(t=='A')  B[M-i+1]=true;
        t=getchar();
    }
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值