题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4055
题干描述:给定一个字符串,要求计算前N个自然数的符合字符串要求的排列数
思考:
首先这是一个dp题,N最大为1000所以可以开二维数组,然后定义f[i][j]为第i位为j的结果
问题是这里存在了当j为k时前面是否存在k这种情况并且如何排除,这是一个难点
思路是通过网上看别人的分析后理解的,将前i-1个数中>=k的数+1这样就不影响结果
之后是状态方程
然而利用这个过程TLE了因为存在三重循环n^3显然会超,然后发现上述过程中的求和过程多次计算可以利用前一项保存结果(I-> D<- ?->)
题干描述:给定一个字符串,要求计算前N个自然数的符合字符串要求的排列数
思考:
首先这是一个dp题,N最大为1000所以可以开二维数组,然后定义f[i][j]为第i位为j的结果
问题是这里存在了当j为k时前面是否存在k这种情况并且如何排除,这是一个难点
思路是通过网上看别人的分析后理解的,将前i-1个数中>=k的数+1这样就不影响结果
之后是状态方程
void dp(){
int len=strlen(buf);
len=len+1;
f[1][1]=1;
for(int i=2;i<=len;i++){
for(int j=1;j<=i;j++){
if(buf[i-2]!='I')
for(int k=j;k<i;k++)
f[i][j]+=f[i-1][k];
if(buf[i-2]!='D')
for(int k=1;k<j;k++)
f[i][j]+=f[i-1][k];
f[i][j]%=base;
}
}
}
然而利用这个过程TLE了因为存在三重循环n^3显然会超,然后发现上述过程中的求和过程多次计算可以利用前一项保存结果(I-> D<- ?->)
以下为ac代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MEMSET(a) memset(a,0,sizeof(a))
const int MAXN=1005;
char buf[MAXN];
long long int f[MAXN][MAXN];
const long long int base=1000000007;
void dp(){
int len=strlen(buf);
len=len+1;
f[1][1]=1;
for(int i=2;i<=len;i++){
if(buf[i-2]=='I')
for(int j=1;j<=i;j++)
f[i][j]=(f[i-1][j-1]+f[i][j-1])%base;
else if(buf[i-2]=='D')
for(int j=i;j>=1;j--)
f[i][j]=(f[i-1][j]+f[i][j+1])%base;
else{
int sum=0;
for(int k=1;k<=i-1;k++)
sum=(sum+f[i-1][k])%base;
for(int j=1;j<=i;j++)
f[i][j]=sum;
}
}
}
int main(){
//freopen("input.txt","r",stdin);
MEMSET(buf);
while(~scanf("%s",buf)){
MEMSET(f);
dp();
int n=strlen(buf)+1;
long long sum=0;
for(int i=1;i<=n;i++)
sum=(sum+f[n][i]);
printf("%lld\n",sum%base);
}
return 0;
}