【数位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

时间: 2024-10-14 12:36:59

【数位DP】bnuoj 52813 J. Deciphering Oracles的相关文章

BZOJ 1833 数位DP

思路: 数位DP f[i][j][k]表示走到第i位 开头位j 数字k 出现的次数 $f[i][j][k]+=f[i-1][l][k];$$f[i][j][j]+=base[i]$ calc的时候要有特殊的技巧...(我看题解学会的) //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int

Tsinsen A1516. fx 数位dp

题目: http://www.tsinsen.com/A1516 A1516. fx 时间限制:2.0s   内存限制:256.0MB 总提交次数:164   AC次数:72   平均分:51.28 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 中国国家队清华集训 2013-2014 第四天 问题描述 对于一个n位的十进制数x(AnAn-1……A1),我们定义它的权重为: F(x)=An*2n-1+An-1*2n-2+……+A1*20 现在,给你两个十进制数A和B,请计算

BNUOJ 52325 Increasing or Decreasing 数位dp

传送门:BNUOJ 52325 Increasing or Decreasing题意:求[l,r]非递增和非递减序列的个数思路:数位dp,dp[pos][pre][status] pos:处理到第几位 pre:前一位是什么 status:是否有前导零 递增递减差不多思路,不过他们计算的过程中像5555,444 这样的重复串会多算,所以要剪掉.个数是(pos-1)*9+digit[最高位],比如一位重复子串是:1,2,3,4...9,9个,二位重复子串:11,22,33,44,...,99,9个:

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

51nod1043(数位dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1043 题意:中文题诶- 思路:数位dp 我们用dp[i][j]来存储长度为2*i且一半和为j的所有情况(包括前导0的情况),为了方便我们现在只讨论其一半的和的情况,因为如果包括前导0的话其两边的情况是一样的: 我们假设再长度为i-1的数字最前面加1位数字k,0<=k<=9(这位数字加在哪里并不影响答案,因为我们在计算i-1长度的时候已经计算了所有组合情况,

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>

【HDU 3652】 B-number (数位DP)

B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task

LightOJ1068 Investigation(数位DP)

这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数 然后就是转移方程,最后就是统计.. 统计部分好棘手...半乱搞下AC的..还是对数位DP的这一部分太不熟悉了. 1 #include<cstdio> 2 #include<cstr

hdu 4734 数位dp

http://acm.hdu.edu.cn/showproblem.php?pid=4734 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, plea