解决本题的关键在于发现给定字符串没啥用,只需考虑长度
由此考虑有两种做法:
- 设 \(f_{i,j}\) 表示敲了 \(i\) 次键盘,得到的恰好为字符串中的前 \(j\) 个的方案数。转移的话考虑最后一步是插入还是删除。若为删除,则必为一个长度为 \(j+1\) 且前 \(j\) 位匹配的字符串,方案为 \(2\times f_{i-1,j+1}\),否则为插入,方案为 \(f_{i-1,j-1}\)
- 考虑到任意一种等长字符串的方案都相同,考虑求出打出任意一个长度为 \(|S|\) 的字符串方案之和并除以 \(2^{|S|}\)
第二种做法的程序:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
x=0;int w=0;char c=getchar();
for(;!isdigit(c);w|=c=='-',c=getchar());
for(;isdigit(c);x=x*10+(c^'0'),c=getchar());
if(w) x=-x;
return in;
}
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
const int N=5005,mod=1e9+7;
typedef long long ll;
char s[N];
int dp[N][N];
void add(int &x,int y){
x+=y;if(x>=mod) x-=mod;
}
ll qpow(ll a,int b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
b>>=1;a=a*a%mod;
}
return ans;
}
int main(){
int n;io>>n;
scanf("%s",s+1);
int len=strlen(s+1);
dp[0][0]=1;
for(int i=1;i<=n;++i){
for(int j=0;j<i;++j){
if(j==0) add(dp[i][j],dp[i-1][j]);
else add(dp[i][j-1],dp[i-1][j]);
add(dp[i][j+1],dp[i-1][j]*2%mod);
}
}
printf("%lld\n",qpow(qpow(2,len),mod-2)*dp[n][len]%mod);
return 0;
}
标签:int,ll,ARC059F,ans,字符串,include,mod
From: https://www.cnblogs.com/pref-ctrl27/p/16921882.html