• 【数位DP】bnuoj 52813 J. Deciphering Oracles


    http://acm.bnu.edu.cn/v3/contest_show.php?cid=9208#problem/J

    【AC】

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 typedef long long ll;
      4 ll N,K;
      5 ll dp[20][200];
      6 ll cnt[200];
      7 int sumdigit(ll x)
      8 {
      9     int tot=0;
     10     while(x)
     11     {
     12         tot+=x%10;
     13         x/=10;
     14     }
     15     return tot;
     16 }
     17 int digit[20];
     18 int split(ll x)
     19 {
     20     int ret=0;
     21     while(x)
     22     {
     23         digit[++ret]=x%10;
     24         x/=10;
     25     }
     26     reverse(digit+1,digit+1+ret);
     27     return ret;
     28 }
     29 
     30 void Dp(int len)
     31 {
     32     memset(dp,0,sizeof(dp));
     33     //从高位到低位递推 
     34     for(int i=1;i<digit[1];i++)//最高位 
     35     {
     36         dp[1][i]=1;
     37     }
     38     int sum=digit[1];
     39     for(int i=2;i<=len;i++)
     40     {
     41         for(int j=0;j<200;j++)
     42         {
     43             if(dp[i-1][j])//不为0才有贡献 
     44                 for(int tran=0;tran<10;tran++)//从高到底第i位 
     45                 {
     46                     if(j+tran<200)
     47                     {
     48                         dp[i][j+tran]+=dp[i-1][j];
     49                     }
     50                 }
     51         }
     52         for(int j=1;j<=9;j++) dp[i][j]++;//因为初始化dp[1][i]时dp[1][0]为0,所以要补上000..j这种情况 
     53         for(int j=0;j<digit[i];j++) dp[i][sum+j]++;//因为初始化dp[1][digit[1]]为0,所以要补上只有第i位不同的情况 
     54         sum+=digit[i];
     55     }
     56     dp[len][sum]++;//算的是小于等于x的数,要加上本身 
     57 }
     58  
     59 ll cal(ll X,int sum,int type)
     60 {
     61     int len=split(X);
     62     Dp(len);
     63     if(type==1)//[1,X]中位数和小于sum的总数 
     64     {
     65         ll ans=0;
     66         for(int i=1;i<sum;i++)
     67         {
     68             ans+=dp[len][i];
     69         }
     70         return ans;
     71     }
     72     else        //[1,x]中位数和恰好为sum的总数 
     73     {
     74         return dp[len][sum];
     75     }
     76 }
     77 
     78 ll solve(ll X,ll k)
     79 {
     80     int len=split(X);
     81     Dp(len);
     82     for(int i=0;i<200;i++)
     83     {
     84         cnt[i]=dp[len][i];
     85     }
     86     for(int i=1;i<200;i++)
     87     {
     88         cnt[i]+=cnt[i-1];
     89     }
     90     ll pos=lower_bound(cnt+1,cnt+200,k)-cnt;
     91     k-=cnt[pos-1];    
     92     ll l=1,r=1e18;
     93     while(l<=r)
     94     {
     95         ll mid=(l+r)>>1;
     96         if(cal(mid,pos,0)<k)
     97         {
     98             l=mid+1;
     99         }
    100         else
    101         {
    102             r=mid-1;
    103         }
    104     }
    105     return l;
    106 }
    107 int main()
    108 {
    109     while(~scanf("%I64d%I64d",&N,&K))
    110     {
    111         cout<<cal(N,sumdigit(K),1)+cal(K,sumdigit(K),0)<<" ";
    112         cout<<solve(N,K)<<endl;    
    113     }
    114     return 0;    
    115 } 
    数位DP
  • 相关阅读:
    js实现页面跳转,location.href和location.replace和location.reload的区别
    Object.create()和new 创建对象的区别
    apply、call、bind区别、用法
    JavaScript toString() 函数详解
    javascript中this指针详解
    javascript中null 和 undefined的区别
    jQuery 图片轮流展示效果
    min-height 兼容
    css 命名规范
    移动端隐藏手机虚拟键盘
  • 原文地址:https://www.cnblogs.com/itcsl/p/7407347.html
Copyright © 2020-2023  润新知