Gym 102040B Counting Inversion(超级数位dp)

问在x,y范围内Σyk=xDI(K)为多少?

DI(K)定义为di>dj&&i<j ,K由dn....d2d1d0构成如DI(123) = 3(d2<d1,d2<d0,d1<d0)DI(253) = 2(d2<d0,d1<d0)

那么我们就数位dp一下,访问所有的数,h[cur][flag][limit]为从状态(u,flag,limit)向后走能到达的状态总数,num[u][flag][limit][i]为状态(cur,flag,limit)及其向后走能到达的所有状态中数字ii出现的总数

#include<bits/stdc++.h>
/*#include<cstring>
#include<set>
#include<map> 
#include<iostream>
#include<algorithm>
#if(__cplusplus == 201103L)
#include <unordered_map>
#include <unordered_set>
#else
#include <tr1/unordered_map>
#include <tr1/unordered_set>
namespace std
{
    using std::tr1::unordered_map;
    using std::tr1::unordered_set;
}
#endif*/ 
#define ll long long
#define mem(a,b) memset(a,b,sizeof a)
#define pb push_back
#define de(x) cout<<x<<endl
#define dd(x) cout<<x<<" "
#define is insert
#define PI acos(-1)
#define ull unsigned long long
using namespace std;
const int maxn =2e5+3;
const int mod = 1e9+7;
typedef pair<ll, ll> p1;
typedef pair< ll, pair<ll,ll > >p2;
inline int rd(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
void out(int a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');}
const int INF = 0x3f3f3f3f;
const ull base = 131;
int MOVE[4][2]={
    {0,1},
    {1,0},
    {0,-1},
    {-1,0},
};

ll ans[20],f,vis[20][2][2],dp[20][2][2],num[20][2][2][11],h[20][2][2],tt;//vis数组是为了防止重复访问,num数组记录每一状态下(0-9)出现的个数h为从状态(cur,flag,limit)向后走能到达的状态总数,dp统计所要求的权值 
void dfs(int cur,bool flag,bool limit)//cur表示位数,flag表示是否有前缀0,limit是否为最大 
{
    if(vis[cur][flag][limit] == tt) return;//如果已经访问过了那么就弹出循环 
    vis[cur][flag][limit] = tt;//还没访问过就标记一下 
    dp[cur][flag][limit] = 0;//对于每一层dp进行清零 
    for(int i=0;i<=9;i++)//对于每层num数组进行清零 
    {
        num[cur][flag][limit][i] = 0;
    }
    if(cur == 0) 
    {
        h[cur][flag][limit] = 1;
        return;
    }
    h[cur][flag][limit] = 0;
    int up = limit?ans[cur]:9;//最大遍历上限 
    for(int i=0;i<=up;i++)
    {
        dfs(cur-1,flag&&i==0,limit&&i==up);
        h[cur][flag][limit] += h[cur-1][flag&&i==0][limit&&i==up];
        for(int j=0;j<=9;j++) num[cur][flag][limit][j]+=num[cur-1][flag&&i==0][limit&&i==up][j];//num统计下一层所出现j的个数 
        dp[cur][flag][limit]+=dp[cur-1][flag&&i==0][limit&&i==up];
        if(!(flag&&(i==0)))//num相加下一层所拥有的数,然后汇总在dp数组上 
        {
            for(int j=0; j<=i; ++j)num[cur][flag][limit][j]+=h[cur-1][flag&&i==0][limit&&i==up];
            dp[cur][flag][limit]+=num[cur-1][flag&&i==0][limit&&i==up][i+1];
        }
    }
    
}
ll solve(ll x)
{
//    mem(dp,0);
//    mem(vis,0);
//    mem(h,0);
//    mem(num,0); 
    int count = 0;
    ++tt;
    // 把所有数字存入数组中 
    while(x)
    {
        ans[++count] = x%10;
        x/=10;
    }
    dfs(count,1,1);
    return dp[count][1][1];
}
void run()
{  
    ll a,b;
    cin >>a>>b;
    printf("Case %lld: %lld
",f,solve(b)-solve(a-1));
    f++;
    //cout<<tt<<endl;
} 
signed main()
{
    //std::ios::sync_with_stdio(false);
    int t = rd();
    f = 1;
    while(t--)
        run();
 } 
原文地址:https://www.cnblogs.com/lcsdsg/p/14534421.html