Harmony Pairs(数位dp)

https://ac.nowcoder.com/acm/contest/5671/H

Harmony Pairs(数位dp)_第1张图片

解析:

d p [ i ] [ j ] dp[i][j] dp[i][j]表示 i i i位数十进制和为 j j j的方案数
l i m i t [ i ] [ j ] limit[i][j] limit[i][j]表示被限制(前面都到达上限,即第1位需要小于等于对应位置数字)的 i i i位数十进制和为 j j j的方案数
s u m [ i ] [ j ] = ∑ k = 1 j d p [ i ] [ k ] sum[i][j]=\sum_{k=1}^jdp[i][k] sum[i][j]=k=1jdp[i][k]
a n s [ i ] ans[i] ans[i]表示 i i i位数的答案( A , B A,B A,B都是 i i i位,不受限)

dfs第p位时:

答案分为:(x代表A的位,y代表B的位,K表示这一位后面的数的长度,h表示当前位的数字,inf上限为接下来数的最大值=9K)

  • 当前位 x < y xx<y,且 y ≠ h y\not=h y=h
    ∑ x = 0 h − 2 ∑ y = x + 1 i ∑ i = y + 1 − x i n f ∑ j = 0 x + i − y − 1 d p [ K ] [ i ] ∗ d p [ K ] [ j ] \sum_{x=0}^{h-2}\sum_{y=x+1}^i\sum_{i=y+1-x}^{inf}\sum_{j=0}^{x+i-y-1}dp[K][i]*dp[K][j] x=0h2y=x+1ii=y+1xinfj=0x+iy1dp[K][i]dp[K][j]
    这个式子自己拆开后发现很多部分是重复的,最后每一位的处理时间为 h ∗ i n f = 9 h K h*inf=9hK hinf=9hK
  • 当前位 x < y xx<y,且 y = h y=h y=h
    ∑ x = 0 h − 2 ∑ i = h + 1 − x i n f ∑ j = 0 x + i − h − 1 d p [ K ] [ i ] ∗ l i m i t [ K ] [ j ] \sum_{x=0}^{h-2}\sum_{i=h+1-x}^{inf}\sum_{j=0}^{x+i-h-1}dp[K][i]*limit[K][j] x=0h2i=h+1xinfj=0x+ih1dp[K][i]limit[K][j]
  • 当前位 x = y x=y x=y
    ∑ x = 0 h − 1 a n s [ K ] \sum_{x=0}^{h-1}ans[K] x=0h1ans[K]

ans的处理和上面这个类似,limit和dp也比较简单。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-07-27-13.25.56
 */
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/

int len;
char x[109];

void Add(LL &a,LL b){
    a=a+b;
    while(a>=mod)a-=mod;
}

LL mxbit[109];
LL dp[109][909]; // mx=900
LL sumdp[109][909];
LL limit[109][999];
LL sumlimit[109][999];
LL ans[109];

void initdfs(int p){
    if(p==len){
        rep(i,0,x[len])
            limit[1][i]=1;
        return;
    }
    initdfs(p+1);

    int res=len-p+1;
    rep(i,0,x[p]-1){
        rep(j,0,mxbit[res-1]){
            limit[res][j+i]=(limit[res][j+i]+dp[res-1][j])%mod;
        }
    }
    rep(j,0,mxbit[res-1]){
        limit[res][j+x[p]]=(limit[res][j+x[p]]+limit[res-1][j])%mod;
    }
}

void init(){
    /// dp
    dp[0][0]=1;
    rep(i,1,101){
        rep(j,0,mxbit[i-1]){
            rep(k,0,9){
                dp[i][j+k]=(dp[i][j+k]+dp[i-1][j])%mod;
            }
        }
        mxbit[i]=mxbit[i-1]+9;
    }
    /// limit
    initdfs(1);
    /// sum
    rep(i,1,101){
        sumdp[i][0]=dp[i][0];
        sumlimit[i][0]=limit[i][0];
        rep(j,1,mxbit[i]){
            sumdp[i][j]=(sumdp[i][j-1]+dp[i][j])%mod;
        }
        rep(j,1,mxbit[i]){
            sumlimit[i][j]=(sumlimit[i][j-1]+limit[i][j])%mod;
        }
    }
    /// ans
    ans[1]=0;
    rep(res,2,101){
        rep(st,2,10){
            LL tmp=0;
            rep(i,st,mxbit[res-1]){
                Add(tmp,dp[res-1][i]*sumdp[res-1][i-st]%mod);
            }
            Add(ans[res],tmp*(11-st)%mod);
        }
        Add(ans[res],10*ans[res-1]%mod);
    }
}

LL Ans;
void dfs(int p){
    if(p==len){
        return;
    }
    int res=len-p+1;
    Add(Ans,x[p]*ans[res-1]%mod);
    if(x[p]>=2){
        rep(st,2,x[p]){
            LL tmp=0;
            rep(i,st,mxbit[res-1]){
                Add(tmp,dp[res-1][i]*sumdp[res-1][i-st]%mod);
            }
            Add(Ans,tmp*(x[p]+1-st)%mod);
        }
    }
    if(x[p]>=1){
        rep(st,2,x[p]+1){
            rep(i,st,mxbit[res-1]){
                Add(Ans,dp[res-1][i]*sumlimit[res-1][i-st]%mod);
            }
        }
    }
    dfs(p+1);
}

int digit(int n){
    int res=0;
    while(n){
        res+=n%10;
        n/=10;
    }
    return res;
}
void getReal(int n){
    int res=0;
    rep(i,0,n){
        rep(j,i+1,n){
            if(digit(i)>digit(j))res++;
        }
    }
    printf("real %d\n",res);
}

int main(){
#define TEST_
#ifdef TEST
    int tmp=rd;
    getReal(tmp);
    while(tmp){
        x[++len]=tmp%10;
        tmp/=10;
    }
    reverse(x+1,x+1+len);
#else
    scanf("%s",x+1);
    len=strlen(x+1);
    rep(i,1,len)x[i]=x[i]-'0';
#endif // TEST
    init();

    dfs(1);
    printf("%lld\n",Ans);

    return 0;
}
/// 2121
/*_________________________________________________________end*/

你可能感兴趣的:(DP动态规划)