hdu 4055/ZOJ 3543 Number String (计数DP+手动取模+巧妙)

以下为在HDU上测试的时间,手动取模比%快了不少


dp[i][j]表示长度为i的字符串,最后一个数字为j时的排列种数。

字符为 I

如果长的为i-1的字符串都排好了的话,第j位只要找第i-1位的数字比j小的就行

所以就是  dp[i][j]=d[i-1][1]+ d[i-1][2]+ d[i-1][3]+...+d[i-1][j-1]  

字符为 D 时

如果长的为i-1的字符串都排好了的话,只要找第i-1位大于等于j的就行

为什么呢,重点来了

你只要把 j~i-1 每个数都 +1 就变成比 j 大的了!!!而且还顺便把j的位置腾出来了!!!十分的巧妙啊!!!

字符为 ?时只要把之前两种情况加起来就行了

最后用前缀和处理一下储存数据就行了。将复杂度降到了N²

#include
using namespace std;
#define ll long long 
#define mod 1000000007
ll dp[1005][1005];ll sum[1005][1005];

inline int MOD(int x){
    if(x >= 0 && x < mod) return x;
    return x < 0 ? -MOD(-x) + mod : x - mod;
}


int main()
{
    char str[1005];  
    while(scanf("%s",str) != EOF){  
        dp[1][1]=1;
        sum[1][1]=1;
        int len=strlen(str);
        for(int i=2;i<=len+1;i++)
        
        for(int j=1;j<=i;j++)
        {
            if(str[i-2]=='I')
            dp[i][j]=MOD(sum[i-1][j-1]);
            else if(str[i-2]=='D')
            dp[i][j]=MOD(sum[i-1][i-1]-sum[i-1][j-1]+mod);
            else
            dp[i][j]=sum[i-1][i-1];
            
            sum[i][j]=MOD(sum[i][j-1]+dp[i][j]);
        }
        printf("%lld\n",sum[len+1][len+1]);
    }
    return 0;
}



你可能感兴趣的:(DP)