ZOJ 2599 Graduated Lexicographical Ordering (数位DP)
首先要吐两行槽:看到集训队论文上有这道题,由于数位DP一律写成记忆化搜索形式的强迫症,就没去看论文上的几个函数是什么……;结果被这道题虐的脑细胞死光……,最后是用随机数据对拍AC程序然后发现BUG改掉后才过掉的,花了一整天时间……。回头看论文,发现差不多……。
大概题意:给出一个long long范围的数N构成区间[1,N]和K(K<N),然后给出数的排名规则(参见原题),看到第一问求K的排名,稍稍考虑后觉得……这还用做?,第二问求第K大的数是什么,脑补N久之后感叹……这也能做?! 好吧,第一问是挺经典的数位统计问题,较简单,第二问,比较困难,很锻炼逆向思维。
思路:第一问大体解题轮廓:如果求出了位数为i,数位和为j的个数,然后把K按区间划分……,差不多是这样。细节处理:K的各位和为SUM,比SUM小的都加上,等于SUM字典序小于K的也加上……于是把比K排名小的数拆成这两部分计算会比较简单,设dp[i][j]为i位小于j的个数(含前导零),dp2[i][j]为i位等于j的个数(不含前导零)……,(其实dp2[i][j]可以用dp[i][j+1]-dp[i][j]表示,为了思路清晰就分开存了……,而且记忆化搜索懒惰求dp值的话,应该会出错……),第一部分区间划分比较简单,只需要考虑别超过N的限制就OK了,所以记忆化搜索只需要设一个标志f1:划分上界不超过N。第二部分繁琐些……,而且需要考虑当前是否有前导零(不明白的仔细考虑一下),觉得至少需要三个标志:f1:前导零标志,f2:划分上界不超过K(字典序限制),f3:划分上界不超过N……。这样就差不多了……
第二问大体解题轮廓:根据排名算数是不能按数位处理的……,所以要倒过来想:排名为K的数的SUM是多少?字典序又是如何的? 排名为K的SUM用第一问的第一个函数就能求出,枚举SUM的值判断是否大于K,大于K就停下,由于dp[i]数组的值是单调的,所以可以二分处理……。设SUM=X,那么第K个数就是SUM=X的所有数中字典序排名为(K-数位和<sum)的……,设这个排名为DX。然后这就又可以利用第一问的第二个函数去按位夹逼……,其实枚举每一位的值时也有单调性,可以二分,不过只枚举0~9,就没这必要了吧……,万一二分再写错……。细节注意:把SUM分配给每一位,SUM减到零时并不一定就是所求,可能还有后导零……。
不知道怎么说的更清楚点了……,还是多动脑想细节吧……。
#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
typedef long long ll; ll dp[][];
ll dp2[][];
int d1[],d2[];
ll dfs(int w,int sum,bool f1)
{
if(sum<=)return ;
if(!w)return sum>;
if(!f1&&~dp[w][sum])return dp[w][sum];
int e=f1?d1[w]:;
ll ans=;
for(int i=;i<=e;++i)
ans+=dfs(w-,sum-i,f1&&(i==e));
if(!f1)dp[w][sum]=ans;
return ans;
} ll dfs2(int w1,int w2,int sum,bool f1,bool f2,bool f3)
{
if(sum<)return ;
if(!w1)return sum==;
if(!f2&&!f3&&~dp2[w1][sum])return dp2[w1][sum];
int e=f3?d1[w1]:;
ll ans=;
if(f2)e=min(e,d2[w2]);
for(int i=;i<=e;++i)
{
if(!i&&f1)ans+=dfs2(w1-,w2,sum,,,);
else ans+=dfs2(w1-,w2+,sum-i,,f2&&(i==d2[w2]),f3&&(i==d1[w1]));
}
if(!f2&&!f3)dp2[w1][sum]=ans;
return ans;
} ll cal(ll n,ll m)
{
int c1,c2,sum;
for(c1=;n;d1[++c1]=n%,n/=);
for(c2=,sum=;m;d2[++c2]=m%,sum+=d2[c2],m/=);
d2[c2+]=-;
for(int i=;i<c2/;++i)swap(d2[i+],d2[c2-i]);
return dfs(c1,sum,)-+dfs2(c1,,sum,,,);
}
ll cal2(ll n,ll k)
{
int c1,c2=;
for(c1=;n;d1[++c1]=n%,n/=);
int l=,r=,m=(l+r)>>;
while(r>l)
{
if(dfs(c1,m,)->=k)r=m;
else l=m+;
m=(l+r)>>;
}
// the kth sum is m-1
int sum=--m;
ll dx=k-(dfs(c1,m,)-);
memset(d2,-,sizeof(d2));
while(sum>)
{
for(d2[c2]=min(sum,);d2[c2]>=;--d2[c2])
if(dx>dfs2(c1,,m,,,))break;
sum-=d2[c2++];
}
if(dfs2(c1,,m,,,)!=dx)
{
bool flag=false;
if(c2>&&d2[c2-]==&&d2[c2-]<)
{
ll t=d2[c2-];
d2[--c2-]+=t,d2[c2]=-;
if(dfs2(c1,,m,,,)==dx)flag=true;
else d2[c2-]-=t,d2[c2++]=t;
}
if(!flag)
do{d2[c2++]=;}while(dfs2(c1,,m,,,)!=dx);
}
ll ans=;
for(int i=;i<c2;++i)
ans*=,ans+=d2[i];
return ans;
}
int main()
{
ll n,m;
memset(dp,-,sizeof(dp));
memset(dp2,-,sizeof(dp2));
while(~scanf("%lld%lld",&n,&m)&&(n+m))
printf("%lld %lld\n",cal(n,m),cal2(n,m));
return ;
}
ZOJ 2599 Graduated Lexicographical Ordering (数位DP)的更多相关文章
- ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)
题意 定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小.输入n,k,求:1.数字k的排名:2.排名为k的数. 思路 算是一类经典的统计问题的拓展吧~ 先来看第一问. ...
- ZOJ2599:Graduated Lexicographical Ordering(很经典的数位DP)
Consider integer numbers from 1 to n. Let us call the sum of digits of an integer number its weight. ...
- ZOJ 3494 (AC自动机+高精度数位DP)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494 题目大意:给定一些被禁止的BCD码.问指定范围内不含有 ...
- zoj 3962 Seven Segment Display 数位dp
非常好的一个题,可以比赛时想到的状态太奇葩,不方便转移,就一直没能AC. 思路:dp(i, j)表示已经考虑了前i位,前i位的和为j的贡献.如果当前的选择一直是最大的选择,那么就必须从0~下一位的最大 ...
- ZOJ 3494 BCD Code (数位DP,AC自动机)
题意: 将一个整数表示成4个bit的bcd码就成了一个01串,如果该串中出现了部分病毒串,则是危险的.给出n个病毒串(n<=100,长度<21),问区间[L,R]中有几个数字是不含病毒串的 ...
- ZOJ 3494 BCD Code(AC自动机+数位DP)
BCD Code Time Limit: 5 Seconds Memory Limit: 65536 KB Binary-coded decimal (BCD) is an encoding ...
- ZOJ 3962 Seven Segment Display(数位DP)题解
题意:给一个16进制8位数,给定每个数字的贡献,问你贡献和. 思路:数位DP,想了很久用什么表示状态,看题解说用和就行,其他的都算是比较正常的数位DP. 代码: #include<iostrea ...
- ZOJ 3962 Seven Segment Display(数位DP)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3962 题目大意: 有t组数据. 给你一个n,和8位的十六进制数s ...
- ZOJ 3962 E.Seven Segment Display / The 14th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple E.数位dp
Seven Segment Display Time Limit: 1 Second Memory Limit: 65536 KB A seven segment display, or s ...
随机推荐
- Struts2笔记——第一个实例HelloWorld
1.创建新的Dynamic Web项目 ------------------------------------------ 2.struts2框架配置 ------------------- ...
- TCP释放连接的四次挥手过程
TCP断开连接的过程:TCP四次挥手. 数据传输结束后,通信的双方都可释放连接.现在A和B都处于ESTABLISHED状态.A的应用进程先向TCP发出连接释放报文段,主动关闭TCP连接.A把连接释放报 ...
- xpath选择器使用
简单说,xpath就是选择XML文件中节点的方法. 所谓节点(node),就是XML文件的最小构成单位,一共分成7种. - element(元素节点)- attribute(属性节点)- text ( ...
- MYSQL数据库错误代码提示汇总
Mysql出错代码表 1005:创建表失败 1006:创建数据库失败 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1009:不能删除数据库文件导致删除数据库失败 1 ...
- Weblogic控制器的部署
WebLogic的安装 一 WebLogic安装 1. 打开WebLogic安装程序:oepe11_wls1031.exe(我们选用的是WebLogic 10.3g).如图1-1所示: 图1-1 ...
- django中post方法和get方法的不同
当我们提交表单仅仅需要获取数据时就可以用GET: 而当我们提交表单时需要更改服务器数据的状态,或者说发送e-mail,或者其他不仅仅是获取并显示数据的时候就使用POST. 在这个搜索书籍的例子里,我们 ...
- [原]poj-2488-water-DFS
题目大意: 输入一个p*q的棋盘, 行用数字表示, 列用大写字母表示 , 1 <= p*q <= 26, 输出能够把棋盘全部空格走完且每个空格只走一次的字典序最小的路径.不存在则输出“im ...
- ANSI是什么编码?
用Notepad++创建一个文本文件text.txt,其默认编码格式为ANSI(乍看之下,还以为是ASCII呢),输入汉字居然不是乱码: 保存为test.txt,发送给你美国的同事Bob.他也用Not ...
- 《OD学hadoop》Linux基础
一.Linux基本环境 1. Linux常见版本及VMware虚拟机安装Linux系统 2. 虚拟机网络配置(IP地址.主机名.防火墙) 3. 文件基本命令操作 4. 四大远程连接工具使用 二.Lin ...
- Oracle数据库之四
删除记录的SQL语句 delete from 表名[where 条件];(DML) 注意: 如果没有where子句,代表全部删除(慎用). delete也必须commit后才能生效 truncate也 ...