题解:UVA10081 Tight Words

封面

题目翻译:

点击查看

思路:

使用动态规划,计算在给定的字母表上,长度为 nn 的所有可能单词中,“紧致”单词的数量。

然后,通过这个数量除以所有可能的单词数量来计算出“紧致”单词的百分百。

对于 dpi,jdp_{i,j},其中 ii 表示长度为 iijj 表示以 jj 结尾,当长度为 11 时,每个数字 jj 都是一个“紧致”单词,因此我们可以初始化所有 dp1,jdp_{1,j}11,其中 0jk0 \le j \le k

对于 ii 不等于 11 时的 dpi,jdp_{i,j} 等于什么呢?这需要分类讨论。

对于长度为 ii 且以数字 jj 结尾的单词,它可以从以下几种情况转移而来:

  1. 长度为 i1i-1 且以数字 jj 结尾的单词。
  2. 长度为 i1i-1 且以数字 j1j-1 结尾的单词,注意 jj 需要大于 00
  3. 长度为 i1i-1 且以数字 j+1j+1 结尾的单词,注意 jj 需要小于 kk

因此,动态转移方程在 c++ 中可以表示为:

dp[i][j]+=dp[i-1][j];
if(j!=0)dp[i][j]+=dp[i-1][j-1];
if(j!=k)dp[i][j]+=dp[i-1][j+1];

代码:

#include<bits/stdc++.h>
using namespace std;
int n,k;
double dp[110][15];
void solve(){
memset(dp,0,sizeof(dp));
for(int i=0;i<=k;i++)dp[1][i]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<=k;j++){
dp[i][j]+=dp[i-1][j];
if(j!=0)dp[i][j]+=dp[i-1][j-1];
if(j!=k)dp[i][j]+=dp[i-1][j+1];
}
}
double sum=0;
double kn=pow(k+1,n);
for(int i=0;i<=k;i++)sum+=dp[n][i];
// cout<<sum<<" "<<kn<<"\n";
double ans=sum*100;
ans/=kn;
printf("%.5lf\n",ans);
// cout<<fixed<<setprecision(5)<<(sum*100.0)/kn<<"\n";
return;
}
int main(){
while(cin>>k>>n)solve();
return 0;
}