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. Python学习日记之练习代码

    # -*- coding:utf-8 -*- number = 23 test=True while test: guess=int(raw_input('输入数字')) if guess==numb ...

  2. PHP开发心得四

    1,php返回给html页面的Json数据不能含有回车符 某次用php编写查询数据库数据,以json格式返回给前端页面js文件,js文件以angularJS的函数调用处理的方式进行数据显示,但数据返回 ...

  3. Fiddler——基本常识

    web session界面 inspector面板 xml:查看XML数据 json:查看json数据 raw:可以完整查看请求的内容 cookies:可以查看请求的cookie header:查看请 ...

  4. C# datagrideview插件的使用

    private void btnLogin_Click(object sender, EventArgs e) { string txtUserName = this.txtUserName.Text ...

  5. Linux系统命令及文件的浏览、管理和维护

    在linux中什么是一个文件的路径呢,说白了就是这个文件存在的地方,例如在上一章提到的/root/.ssh/authorized_keys 这就是一个文件的路径.如果你告诉系统这个文件的路径,那么系统 ...

  6. NFV

    转载: NFV介绍定义:NFV,即网络功能虚拟化,Network Function Virtualization.通过使用x86等通用性硬件以及虚拟化技术,来承载很多功能的软件处理.从而降低网络昂贵的 ...

  7. 关于ISIS协议 CSNP报文的周期更新理解

    为何ISIS协议的CSNP报文在MA网络环境中是以周期更新然而在P2P网络环境中只更新一次? 个人通过视频及资料学习理解: 我们知道ISIS的CSNP报文类似OSPF中的DBD报文,作用就是用来确认彼 ...

  8. jieba的基本使用

    目录 1.分词 2.添加自定义词典 3.关键词提取 4.词性标注 jieba 是一款优秀的 Python 第三方中文分词库,可以使用 pip install jieba / pip3 install ...

  9. Python判断字符串是否全是字母或数字

    str.isnumeric(): True if 只包含数字:otherwise False.注意:此函数只能用于unicode string str.isdigit(): True if 只包含数字 ...

  10. 57.fielddata预加载机制以及序号标记预加载

    如果真的要对分词的field执行聚合,那么每次都在query-time的同时由es生成fielddata并加载到内存中来,速度可能会比较慢,性能很差,改善性能的方式就是预先生成fielddata值并加 ...