题目的链接:http://exam.upc.edu.cn/problem.php?cid=1371&pid=6
题意:给你N次敲键盘的机会,给定字符串s,让你敲出这个代码的方案数的。
输入只有0 、1或者 退格键(Backspace).
题解:
在此之前真的要感谢一下SQY学长。https://blog.youkuaiyun.com/xs18952904/article/details/80358749
要是没有他每天写的博客,我还真不知道有些题是怎么写出来的。在此膜拜一遍。
需要用到 dp[0~n][0~len]---第一维指的是:第n次敲键盘,len是当前的长度。
输入 0或1 是:dp[i+1][j+1]=dp[i][j]+dp[i+1][j+1];
退格键(Backspace): dp[i+1][j-1]=dp[i][j]+dp[i+1][j-1];
为什么标记为红色呢:因为当j==0时会越界。所以max(j-1,0);
还有一点要注意。
推出了dp[n][len]后,因为要得到这个字符串只有一种情况,而我们是0或1乱来了
所以 ans=(dp[n][len])/(qpow(2,len));
运用费马小定理:qpow(qpow(2,len),mod-2);
ans=dp[n][len]*qpow(qpow(2,len),mod-2);
这题还需要mod 防爆。
再次感谢SQY学长要不然这题一直做不出来。
贴上代码:
#include<bits/stdc++.h>
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll qpow(ll a,int b){
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}return ans;
}
int dp[5050][5050]={0};
int n,len;
char s[5050];
int main()
{
scanf("%d%s",&n,s);
len=(int)strlen(s);
dp[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++){
dp[i+1][j+1]=(int)(( 2ll*dp[i][j]%mod + dp[i+1][j+1] )%mod);
dp[i+1][max(j-1,0)]=(int)(( 0ll+dp[i][j]+dp[i+1][max(j-1,0)])%mod);
}
}
/*for(int i=0;i<=4;i++){
for(int j=0;j<=4;j++){
printf("%d%c",dp[i][j],j==4?'\n':' ');
}
}*/
int ans=(int)(qpow(qpow(2,len),mod-2)*dp[n][len]%mod);
printf("%d\n",ans);
return 0;
}