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 ...
随机推荐
- Java-J2SE学习笔记-查找一个String中,subString的出现次数
1.查找一个String中,subString的出现次数 2.代码 package Test; public class TestStringContain { public static void ...
- iOS LLDB调试器和断点调试
技巧一:运行时修改变量的值 你以前怎么验证是不是某个变量的值导致整段程序不能正常工作?修改代码中的变量的值,然后cmd+r重新启动app?现在你不需要这么做了,只需要设置一个断点,当程序在这进入调试模 ...
- Database File Management ->> Shrink Data File
今天在开发环境遇到了一个问题,我们发现服务器上的硬盘空间满了,查看了下发现这个盘存放的数据库文件应该是来源一个并非很大的库才对.检查之后发现这个数据库下的某个数据文件占了盘符下70%的空间,而大部分数 ...
- 如何在Java 8中愉快地处理日期和时间
Java 8新增了LocalDate和LocalTime接口,为什么要搞一套全新的处理日期和时间的API?因为旧的java.util.Date实在是太难用了. java.util.Date月份从0开始 ...
- Linux下安装mysql-5.6.4 的图文教程
在开始安装前,先说明一下mysql-5.6.4与较低的版本在安装上的区别,从mysql-5.5起,mysql源码安装开始使用cmake了,因此当我们配置安装目录./configure --perfix ...
- 图像分类之特征学习ECCV-2010 Tutorial: Feature Learning for Image Classification
ECCV-2010 Tutorial: Feature Learning for Image Classification Organizers Kai Yu (NEC Laboratories Am ...
- jdk、apache-ant结合yuicompressor配置的CSS与JS合并压缩工具
前序:网上很多css与js合并打包工具,其中最流行的就是ant结合yui-compressor,鉴于学习与工作需要今天就学习了一下这种方式,供大家学习交流. 步骤:1.安装jdk,并配置其变量环境:有 ...
- javascript 原生方法监听DOM结构改变事件
js原生方法监听DOM结构改变事件 document.addEventListener('DOMNodeInserted',function(){alert(1)},false);document.a ...
- dojo 六 使用query dojo/query
要使用query,就要引入dojo/query包.query可以根据Dom里节点的标签名.id名.class名来检索一个或多个节点.---------------------------------- ...
- android backlight
背光设置是在:设置->声音和显示->亮度,通过进度条来设置的. 文件:packages/apps/Settings/src/com/android/settings/BrightnessP ...