zoukankan      html  css  js  c++  java
  • 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();
     } 
  • 相关阅读:
    前五章的综合(查漏补缺)一个字一个字读,便于您的理解程度
    appium连接android真机【红米note8】碰到的问题及解决方案
    linux tz配置
    linux下卸载apache
    VM下的静态ip和动态ip的坑
    linux下安装mysql
    LR录制过程中会出现的问题
    linux下安装jdk和tomcat
    jmeter的环境变量
    jmeter实现mysql的增删改查
  • 原文地址:https://www.cnblogs.com/lcsdsg/p/14534421.html
Copyright © 2011-2022 走看看