一道有点考思维的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();
}