H Harmony Pairs(找(大小)和(位数和大小)逆序的点对,数位dp)

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

题意:定义S(x)为x作为十进制的各个位数之和,问1~n中多少点对满足S(A)>S(B)   (0<=A<=B<=N)(1<=N<=10^100);

分析:字符串范围,考虑数位dp,dp[i][j][limit1][limit2][statue],代表枚举到最高位为i,俩者数码和之差为j,A和N的关系为limit1,B和N的关系为limit2,A和B的大小关系为statue时的对数。

   复杂度:O(len2103

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define MP make_pair
typedef long long ll;
const int mod=1e9+7;
const int M=102;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
ll dp[M][2002][3][3][3];
int a[M];
char s[M];
ll dfs(int pos,int dis,int limit1,int limit2,int statue){
    if(pos==-1)
        return dis>0;
    if(~dp[pos][dis+1000][limit1][limit2][statue])
        return dp[pos][dis+1000][limit1][limit2][statue];
    int up1=(limit1?a[pos]:9);
    int up2=(limit2?a[pos]:9);
    ll ans=0;
    for(int i=0;i<=up1;i++){
        for(int j=(statue?i:0);j<=up2;j++)
            ans=(ans+dfs(pos-1,dis+i-j,limit1&&(i==a[pos]),limit2&&(j==a[pos]),statue&&(i==j)))%mod;
    }
    return dp[pos][dis+1000][limit1][limit2][statue]=ans%mod;
}
int main(){
    memset(dp,-1,sizeof(dp));
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++)
        a[i]=s[len-1-i]-'0';
    printf("%lld
",dfs(len-1,0,1,1,1));
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13392045.html