zoukankan      html  css  js  c++  java
  • Codeforces 611D New Year and Ancient Prophecy DP

    题意:

    把一个字符串分割成多个小串,小串组成严格递增序列,n<=5000

    这是一个DP。

    s代表原串

    dp[i][j]代表当前到i位置最后一个串是以j为开头的方案数。答案就是dp[n][1]+...+dp[n][n]

    很容易得到dp[i][j]=dp[j-1][k]+dp[j-1][k+1]……dp[j-1][j-1]    (i-j=j-k) 如果s[k-1....j-1] >=s[j....i], dp[i][j]+=dp[j-1][k-1]

    这样dp的递推式就有了,很容易发现dp[i][j]的递推式是一个前缀和,假设我比较s[k-1....j-1]和s[j....i]是O(1) 那么就可以在n^2的复杂度里得到答案

    所以问题转化为如何预处理以x为开头的串和以y为开头的串的大小(x<y)

    令r[x][y]为以x开头的串和以y开头的串经过多少长度分出大小,is[x][y]为true代表x小,为false代表y小

    if(r[x-1][y-1]>0) r[x][y]=r[x-1][y-1]-1,is[x][y]=is[x-1][y-1];

    else 暴力跑出r[x][y]    

    所以对于每一个r[1][y]我们得出r[2][y+1]...r[n-y+1][n]的复杂度是O(n)

    所以求出r[1][1]....r[1][n]

    然后有了所有的is(x,y) 就可以O(1)比较以x和y开头的子串大小

    具体代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=5005;
    const long long MOD=1000000007;
    long long dp[N][N];
    int r[N][N];
    bool is[N][N];
    char s[N];
    char a[N],b[N];
    int l1,l2,n;
    int main()
    {
        int i,j,k;
        while(scanf("%d",&n)!=EOF)
        {
            scanf("%s",s+1);
            for(i=1;i<=n;i++) dp[i][1]=1;
            for(j=2;j<=n;j++)
            {
                is[1][j]=false;
                for(k=0;k+j<=n;k++)
                {
                    if(s[1+k]>s[j+k]) {is[1][j]=false;r[1][j]=k;break;}
                    if(s[1+k]<s[j+k]) {is[1][j]=true;r[1][j]=k;break;}
                }
                if(k+j>n) r[1][j]=n+1;
            }
            for(k=1;k<n;k++)
            {
                for(i=2;i+k<=n;i++)
                {
                    if(r[i-1][i+k-1]) {is[i][i+k]=is[i-1][i+k-1];r[i][i+k]=r[i-1][i+k-1]-1;}
                    else
                    {
                        is[i][i+k]=false;
                        for(j=0;i+j<=n&&i+k+j<=n;j++)
                        {
                            if(s[i+j]>s[i+k+j]) {is[i][i+k]=false;r[i][i+k]=j;break;}
                            if(s[i+j]<s[i+k+j]) {is[i][i+k]=true;r[i][i+k]=j;break;}
                        }
                        if(i+k+j>n) r[i][i+k]=n+1;
                    }
                }
            }
            for(i=2;i<=n;i++)
            {
                k=i;
                if(s[i]=='0') continue;
                long long sum=0;
                for(j=i;j<=n;j++)
                {
                   if(k>0) sum+=dp[i-1][k];
                   if(sum>=MOD) sum%=MOD;
                   k--;
                   dp[j][i]+=sum;
                   if(k>0&&s[k]=='0') continue;
                   int flag=0;
                   if(k>0)
                   {
                     if(is[k][i]==true&&r[k][i]+k<i) flag=1;
                   }
                   if(flag) dp[j][i]+=dp[i-1][k];
                   if(dp[j][i]>=MOD) dp[j][i]%=MOD;
                }
            }
            long long ans=0;
            for(i=1;i<=n;i++)
            {
                ans+=dp[n][i];
                if(ans>=MOD) ans%=MOD;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    HDU 5585 Numbers
    HDU 3308 LCIS
    POJ 2991 Crane
    POJ 1436 Horizontally Visible Segments
    POJ 3667 Hotel
    HaiHongOJ 1003 God Wang
    【SDOI 2008】 递归数列
    5月19日省中提高组题解
    【HDU 1588】 Gauss Fibonacci
    【POJ 3233】Matrix Power Series
  • 原文地址:https://www.cnblogs.com/Woo95/p/5094637.html
Copyright © 2011-2022 走看看