數字分割

【題目描述】
ios

  給定一個很大的數字,有n位,你的任務就是將這個數字分割成若干段,分割的要求有2點:git

  一、分割後數字從左到右嚴格遞增 spa

  二、每段分割數字不能有前導0 例如數字123434有8種分割方式,code

  分別爲: blog

    "123434"
    "1" + "23434"
    "12" + "3434"
    "123" + "434"
    "1" + "23" + "434"
    "1" + "2" + "3434"
    "1" + "2" + "3" + "434"
    "1" + "2" + "3" + "4" + "34"get

  統計有多少種分割方式,因爲答案太大,對答案取模10^9+7。string

這是今天比賽T3,也是惟一A掉的一道題...(雖然是非正解,但比賽時卡了一波常在0.1s內A了...出題人要卡的話會被卡成O(${n}^3$)...)it

DP問題,咱們用dp[i][len]表示第i爲開始長度爲n的答案的個數io

狀態轉移:ast

dp[i][len]=$\Sigma$dp[i][len]+dp[i-k][k]

其中k在[1,len]之間,且要知足單調遞增的關係

邊界:

  顯然從1開始的任何長度均可以實現,因此dp[1][1...n]=1,其餘爲0

 

 1 #pragma GCC optimize("Ofast")
 2 #pragma GCC optimize(2)
 3 #include<cstdio>
 4 #include<queue>
 5 #include<iostream>
 6 #include<cstring>
 7 #include<algorithm>
 8 const int ha=1e9+7;  9 using namespace std; 10 inline int read(){ 11     int ans=0,f=1;char chr=getchar(); 12     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} 13     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 14     return ans*f; 15 }char s[5005]; 16 int n,dp[5001][5001],ans; 17 inline bool Check(int i1,int len1,int i2,int len2){//判斷和上一個比是否單調增 18     if(len1>len2) return 0; 19     if(len2>len1) return 1; 20     for(register int i=0;i<len1;++i){ 21         if(s[i1+i]!=s[i2+i]) 22             if(s[i1+i]>s[i2+i]) return 0; 23             else return 1; 24     }return 0; 25 } 26 int main(){ 27     n=read(),scanf("%s",s+1); 28     for(register int i(1);i<=n;++i) dp[1][i]=1; 29     for(register int i(2);i<=n;++i){ 30         if(s[i]==48) continue;//不能爲前導0 31         for(register int len(1);i+len-1<=n;++len){//枚舉長度 32             for(register int k(1);k<=min(len,i);++k) 33                 if(Check(i-k,k,i,len)) 34                     dp[i][len]=(dp[i][len]+dp[i-k][k])%ha; 35             if(i+len-1==n) ans=(ans+dp[i][len])%ha;//累加答案 36  } 37     }cout<<(ans+1)%ha;//加1是由於dp[1][n]的值沒有加上去過 38     return 0; 39 } 40 /*
41 6 42 123456 43 */
相關文章
相關標籤/搜索