Consider integer numbers from 1 to n. Let us call the sum of digits of an integer number its weight. Denote the weight of the number x as w(x).

Now let us order the numbers using so called graduated lexicographical ordering, or shorter grlex ordering. Consider two integer numbers a and b. If w(a) < w(b) then a goes before
b in grlex ordering. If w(a) = w(b) then a goes before b in grlex ordering if and only if the decimal representation of a is lexicographically smaller than the decimal representation of b.

Let us consider some examples.

  • 120 < grlex4 since w(120) = 1 + 2 + 0 = 3 < 4 = w(4).
  • 555 < grlex78 since w(555) = 15 = w(78) and "555" is lexicographicaly smaller than "78".
  • 20 < grlex200 since w(20) = 2 = w(200) and "20" is lexicographicaly smaller than "200".

Given n and some integer number k, find the position of the number k in grlex ordering of integer numbers from 1 to n, and the k-th number in this ordering.

Input

There are several lines in the input file, and each line stands two integers n and k (1 <= k <= n <= 1018). A line with n = k = 0 ends up the input.

Output

For each line in the input, output one line in the output file. First print the position of the number k in grlex ordering of integer numbers from 1 to n, and then the integer that occupies
the k-th position in this ordering.

Sample Input

20 10
0 0

Sample Output

2 14


题意:先把1~n内的数依照数位和排一次序。然后数位和相等的依照字典序拍一次序,然后输出k的位置和第k个位置的数

这道题在高逸涵的论文《数位计数问题解法研究》中有
他给出了5个函数

1. getSum1(int L, int sum); 数字和为 sum 的 L 位数字的个数(以0为前缀的也算数)

2. getSum2(LL n, int sum); 返回 1~n 中数字和为 sum 的数的个数

3. getSum3(LL n, LL prefix, int sum); 返回 1~n 中数字和为 sum 前缀为 prefix 的数的个数

4. getSum4(LL n, LL k, int sum); 返回 1~n 中数字和为 sum 且字典序小于k的数的个数

5. getSum5(LL n, LL k); 返回 k 在 1~n 中的位置

用这五个函数解决这道题
在ZOJ提交后吃惊的发现自己排在d第2,并且与第1的执行时间和内存是一样的,仅仅是他是08年提交的。我是14年提交的


#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define ll __int64
#define up(i,x,y) for(i=x;i<=y;i++)
#define down(i,x,y) for(i=x;i>=y;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define w(x) while(x)
ll n,k;
ll dp[20][200];
//数字和为 sum 的 L 位数字的个数(以0为前缀的也算数)
ll getSum1(int L, int sum)
{
if(sum>9*L || sum<0 || L<0)
return 0;
if(dp[L][sum])
return dp[L][sum];
if(!L&&!sum)
return 1;
int i;
up(i,0,9)
{
if(sum-i<0)break;
dp[L][sum]+=getSum1(L-1,sum-i);
}
return dp[L][sum];
}
// 返回 1~n 中数字和为 sum 的数的个数
ll getSum2(ll n, int sum)
{
int bit[20],i,len=0,j;
ll ans=0;
w(n)
{
bit[len++]=n%10;
n/=10;
}
down(i,len-1,0)
{
up(j,0,bit[i]-1)
ans+=getSum1(i,sum--);
}
ans+=getSum1(0,sum);
return ans;
}
//返回 1~n 中数字和为 sum 前缀为 prefix 的数的个数
ll getSum3(ll n,ll prefix,int sum)
{
char sn[20],sp[20];
int ln,lp,i,j;
ll ans = 0;
sprintf(sn,"%I64d",n);//将数字转化为字符串
sprintf(sp,"%I64d",prefix);
ln=strlen(sn),lp=strlen(sp);
up(i,0,lp-1)
sum-=sp[i]-'0';
up(i,0,lp-1)
if(sn[i]!=sp[i])
break;
if(i<lp)
{
if(sn[i]<sp[i]) ln--;//假设前缀的这一位大于n。那么从第二高位匹配,看作n的长度减去1
down(i,ln-lp,0)
ans+=getSum1(i,sum);
return ans;
}
ll tem=0;
up(i,lp,ln-1)
tem=tem*10+sn[i]-'0';
ans+=getSum2(tem,sum);
down(i,ln-lp-1,0)
ans+=getSum1(i,sum);
return ans;
}
//返回 1~n 中数字和为 sum 且字典序小于k的数的个数
ll getSum4(ll n,ll k,int sum)
{
int bit[20],i,len=0,j,t=1;
ll ans=0,pre=1;
w(k)
{
bit[len++]=k%10;
k/=10;
}
down(i,len-1,0)//枚举前缀
{
up(j,t,bit[i]-1)
{
ans+=getSum3(n,pre++,sum);
}
pre*=10;
t = 0;
}
//比如1000。小于k的有1,10,100这些是在前面统计过程中不涉及的
up(i,0,len-1)
{
if(bit[i]==0)ans++;
else break;
}
return ans;
}
//返回 k 在 1~n 中的位置
ll getSum5(ll n,ll k)
{
ll sum = 0,tem=k,ans=0,i;
while(tem)
{
sum+=(tem%10);
tem/=10;
}
up(i,1,sum-1)//计算全部和小于sum的个数
ans+=getSum2(n,i);
ans+=getSum4(n,k,sum);//和等于sum,可是字典序小于k的个数
return ans+1;//位于那些数的后一个位置
}
int main()
{
mem(dp,0);
w((scanf("%I64d%I64d",&n,&k),n+k))
{
printf("%I64d ",getSum5(n,k));
ll pre=1,presum=1,sum=1,t;
w(((t=getSum2(n,sum))<k))//统计数位和。从1開始,确定第k个位置的数位和
{
sum++;
k-=t;
}
w(1)
{
w(((t=getSum3(n,pre,sum))<k))//确定k位置的数位和后,再比較前缀,找出k位置的数
{
pre++;
presum++;
k-=t;
}
if(presum==sum) break;//数位和确定
pre*=10;
}
w(--k)pre*=10;//由于数位和确定,且前缀同样的情况还有可能是1,10,100这些类型,也要考虑
printf("%I64d\n",pre);
} return 0;
}


ZOJ2599:Graduated Lexicographical Ordering(很经典的数位DP)的更多相关文章

  1. ZOJ 2599 Graduated Lexicographical Ordering (数位DP)

    首先要吐两行槽:看到集训队论文上有这道题,由于数位DP一律写成记忆化搜索形式的强迫症,就没去看论文上的几个函数是什么……:结果被这道题虐的脑细胞死光……,最后是用随机数据对拍AC程序然后发现BUG改掉 ...

  2. ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)

    题意 定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小.输入n,k,求:1.数字k的排名:2.排名为k的数. 思路 算是一类经典的统计问题的拓展吧~ 先来看第一问. ...

  3. hdu3534,个人认为很经典的树形dp

    题目大意为,求一个树的直径(最长路),以及直径的数量 朴素的dp只能找出某点开始的最长路径,但这个最长路径却不一定是树的直径,本弱先开始就想简单了,一直wa 直到我看了某位大牛的题解... 按照那位大 ...

  4. [SCOI2009] windy 数 (数位dp)

    题目 算法 应该是一道很经典的数位dp题 我们设dp[i][j]是填到第i位此时第i位的数是j的方案数 然后进行转移(代码注释) 代码 #include<iostream> #includ ...

  5. 算法复习——数位dp

    开头由于不知道讲啥依然搬讲义 对于引入的这个问题,讲义里已经很清楚了,我更喜欢用那个建树的理解···· 相当于先预处理f,然后从起点开始在树上走··记录目前已经找到了多少个满足题意的数k,如果枚举到第 ...

  6. HDU3555【数位DP】

    入门...还在学习中,先贴一发大牛博客 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意: 给一个数字n,范围在1~2^63-1,求1~ ...

  7. 数位dp相关

    经典的数位Dp是要求统计符合限制的数字的个数. 一般的形式是:求区间[n,m]满足限制f(1). f(2). f(3)等等的数字的数量是多少. 条件 f(i) 一般与数的大小无关,而与数的组成有关. ...

  8. Fzu2109 Mountain Number 数位dp

    Accept: 189    Submit: 461Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description One ...

  9. [kuangbin带你飞]专题十五 数位DP

            ID Origin Title   62 / 175 Problem A CodeForces 55D Beautiful numbers   30 / 84 Problem B HD ...

随机推荐

  1. 如何快速排查解决Android中的内存泄露问题

    概述 内存泄露是Android开发中比较常见的问题,一旦发生会导致大量内存空间得不到释放,可用内存急剧减少,导致运行卡顿,部分功能不可用甚至引发应用crash.对于复杂度比较高.多人协同开发的项目来讲 ...

  2. Indy 编译提示版本不一致问题的解决

    1,起因 某delphi程序A使用了Indy9.0.18组件.机器中原本自带老版本的Indy组件9.0.12,后升级到9.0.18,使用一直正常. 某次操作将程序A重新build all了一下,结果提 ...

  3. vue学习图解

    vue2.0版本的学习图解个人心得!本文为原创禁止转载!!转载需要注明出处,谢谢合作!!!

  4. Xilinx FPGA编程技巧之常用时序约束详解

    1.   基本的约束方法 为了保证成功的设计,所有路径的时序要求必须能够让执行工具获取.最普遍的三种路径为: 输入路径(Input Path),使用输入约束 寄存器到寄存器路径(Register-to ...

  5. linux使用crontab实现PHP执行计划定时任务

    linux使用crontab实现PHP执行计划定时任务 前几天写过一篇文章,利用单纯的php实现定时执行任务,但是效率不佳,对于linux来说用crontab实现更加合理 首先说说cron,它是一个l ...

  6. 【sqli-labs】 less65 GET -Challenge -Blind -130 queries allowed -Variation4 (GET型 挑战 盲注 只允许130次查询 变化4)

    双引号括号闭合 http://192.168.136.128/sqli-labs-master/Less-65/?id=1")%23

  7. Linux下查看CPU信息、机器型号等硬件信息命令

    Linux下查看CPU信息.机器型号等硬件信息命令 编写一个bash脚本: vim info.sh #!/bin/bash cat /etc/issue echo "____________ ...

  8. 12Microsoft SQL Server 索引

    Microsoft SQL Server 索引 8.1创建索引 CREATE INDEX idx_name ON table_name(列名) --创建非聚集索引 use student go cre ...

  9. ocelot+consul+identity4的使用demo

    Ocelot网关搭建 搭建core控制台项目 本demo采用2.1版本 命名为APPIGateWay 在Nuget包中添加Ocelot引用 选用8.0.0版本 添加Ocelot.json 文件 内容为 ...

  10. Python学习笔记(1)对象类型

    强制转换字符串函数str 如果我们求2的一百万次方是多少那么我们可以 print(2**1000000) 如果我们要求2的一百万次方有多少位那么我们可以用str函数强制转换成字符串然后len函数计算 ...