ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)
题意
定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小。输入n,k,求:1.数字k的排名;2.排名为k的数。
思路
算是一类经典的统计问题的拓展吧~
先来看第一问。求数字K的排名,变相得看就是求[1,N]中小于K的数的个数,数位DP统计下即可(记忆化搜索方式,dfs()过程):pos表示处理的位置;dig_sum表示当前枚举的数位和;隐藏的全局比较对象k_sum是K的数位和;start表示枚举数位开始的位置,即第一个非零位,便于按位DP时比较字典序;flag表示字典序是否小于K,-1表示小于,0表示未决定,1表示大于,比较过程在按位DP过程中即完成(详见next_flag计算);limit表示当前数位的数字是否达上限。
然后来看第二问。如果是像此题这样和数大小不成线性关系的排名规则,尝试正着求排名可能会比较麻烦。所以一般处理这种排序问题的方法是用某种方法枚举符合规则的数,然后判断这个数是不是排第K(求一个数的排名用第一问的方法)。一般枚举数可以二分,blablabla……当然这道题二分不行,因为字典序和数位和规则都不具备单调性。而朴素枚举显然不行,在这道题中,大家普遍的方法是枚举前缀~具体一点儿就是:枚举第一位是几,再枚举第二位是几,直到确定这个数字。枚举每一位时都是从0~9(除了第一位不能是0),这样就保证了枚举的顺序符合字典序递增的顺序。而我们也可以通过枚举数位和来算出第K个数的数位和(见代码)。总结一下第二问的思路就是:先算出第K个数的数位和k_dig_num,然后枚举前缀,根据当前前缀、数位和为k_dig_num下的数的个数,由于字典序,所以前面的数一定小于第K个数,这样下去知道当前枚举到的数是第K个数。
代码
[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, end) for (int i = begin; i <= end; i ++)
using namespace std;
typedef unsigned long long LL;
typedef vector <int> VI;
int k_sum, k_dig_sum;
VI num, k_num;
LL dp[25][200][25][5], fsum[25][200];
LL res1, res2;
int sum;
LL dfs(int pos, int dig_sum, int start, int flag, bool limit){
if (pos == -1){
if (dig_sum == 0) return 0;
if (dig_sum > k_sum) return 0;
else if (dig_sum == k_sum){
if (!flag)
if ((int)k_num.size()-1-(start-pos) >= 0)
return 1;
else
return 0;
else{
return (flag==-1)?1:0;
}
}
else if (dig_sum < k_sum) return 1;
}
if (!limit && ~dp[pos][dig_sum][start][flag]) return dp[pos][dig_sum][start][flag];
int end = limit?num[pos]:9; LL res = 0;
REP(i, 0, end){
bool st = (start == pos && i == 0);
int next_flag;
if (flag != 0) next_flag = flag;
else{
if (st) next_flag = 0;
else {
if ((int)k_num.size()-1-(start-pos) < 0) next_flag = 1;
else{
if (i < k_num[(int)k_num.size()-1-(start-pos)]) next_flag = -1;
else if (i == k_num[(int)k_num.size()-1-(start-pos)]) next_flag = 0;
else next_flag = 1;
}
}
}
res += dfs(pos-1, dig_sum+i, st?start-1:start, next_flag, limit&&(i==end));
}
return limit?res:dp[pos][dig_sum][start][flag]=res;
}
LL find_dig_sum(int pos, int dig_sum, bool limit){
if (pos == -1) return dig_sum == sum;
if (!limit && ~fsum[pos][dig_sum]) return fsum[pos][dig_sum];
int end = limit?num[pos]:9;
LL res = 0;
REP(i, 0, end){
res += find_dig_sum(pos-1, dig_sum+i, limit&&(i==end));
}
return limit?res:fsum[pos][dig_sum]=res;
}
inline void cal(LL x){
num.clear();
while(x){
num.push_back(x%10);
x /= 10;
}
}
inline void cal_k(LL k){
k_num.clear();
k_sum = 0;
while(k){
k_sum += k%10;
k_num.push_back(k%10);
k /= 10;
}
}
LL solve_pos(LL n, LL k){
if (k == 0) return 0;
cal_k(k);
cal(n);
MEM(dp, -1);
return dfs(num.size()-1, 0, num.size()-1, 0, 1) + 1;
}
LL solve_rank(LL n, LL k){
LL sum_num = 0;
LL dig_sum_rank = k;
for (sum = 1; sum <= 180; sum ++){
MEM(fsum, -1);
sum_num += find_dig_sum(num.size()-1, 0, 1);
if (sum_num >= k){
k_dig_sum = sum;
if (sum > 1){
dig_sum_rank -= sum_num - find_dig_sum(num.size()-1, 0, 1);
}
break;
}
}
LL testnum = 0, sumranks = 0;
while(solve_pos(n, testnum) != k){
testnum *= 10;
LL ranks = 0;
REP(i, 0, 9){
ranks = 0;
if (testnum == 0 && i == 0) continue;
LL begin = testnum+i;
LL offset = 1;
while(begin<=n){
cal(min(n, begin+offset-1));
ranks += find_dig_sum(num.size()-1, 0, 1);
cal(begin-1);
ranks -= find_dig_sum(num.size()-1, 0, 1);
begin *= 10;
offset *= 10;
}
if (sumranks + ranks >= dig_sum_rank){
testnum = testnum + i;
break;
}
sumranks += ranks;
}
}
return testnum;
}
LL n, k;
int main(){
while(scanf("%lld %lld", &n, &k), n+k){
res1 = res2 = -1;
res1 = solve_pos(n, k);
res2 = solve_rank(n, k);
printf("%lld %lld\n", res1, res2);
}
return 0;
}
[/cpp]
ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)的更多相关文章
- ZOJ 2599 Graduated Lexicographical Ordering (数位DP)
首先要吐两行槽:看到集训队论文上有这道题,由于数位DP一律写成记忆化搜索形式的强迫症,就没去看论文上的几个函数是什么……:结果被这道题虐的脑细胞死光……,最后是用随机数据对拍AC程序然后发现BUG改掉 ...
- 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游戏服务器成长之路——感悟篇
又是一个美好的周末啊,现在一到周末,早上就起得晚,下午困了又会睡一两个小时,上班的时候,早上起来喝一杯咖啡,然后就能高效的工作一整天,然而到了周末人就懒散了,哈哈. 最近刚跳槽,到新公司已经干了有两周 ...
- 基于wtforms源码实现自定义form组件
from flask import Flask,Markup,render_template,request,redirect from wtforms.form import Form from w ...
- sql 自定义函数返回中文,数字,英文
--提取数字IF OBJECT_ID('DBO.GET_NUMBER2') IS NOT NULLDROP FUNCTION DBO.GET_NUMBER2GOCREATE FUNCTION DBO. ...
- LINQ查询中的IEnumerable<T>和IQueryable<T>
LINQ查询方法一共提供了两种扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展:Queryab ...
- 『NiFi 自定义 Processor 无法获取到 Logger』问题解决
一.概述 自定义的 Processor 继承了 AbstractProcessor,而 AbstractProcessor 继承了 AbstractSessionFactoryProcessor ,g ...
- CodeForces - 528D Fuzzy Search (FFT求子串匹配)
题意:求母串中可以匹配模式串的子串的个数,但是每一位i的字符可以左右偏移k个位置. 分析:类似于 UVALive -4671. 用FFT求出每个字符成功匹配的个数.因为字符可以偏移k个单位,先用尺取法 ...
- IOS开发-数据库总结
关于数据存储概念: 数据结构: 基本对象:NSDictionary.NSArray和NSSet这些对象. 复杂对象:关系模型.对象图和属性列表多种结构等. 存储方式: 内存:内存存储是临时的,运行时有 ...
- CSS Position(定位)
CSS Position(定位) 一.CSS Position(定位) position 属性指定了元素的定位类型. position 属性的五个值: static relative fixed ab ...
- CSS Outline(轮廓)
CSS Outline(轮廓) 一.CSS 轮廓(outline) 轮廓(outline)是绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用. CSS outline 属性规定元素轮廓 ...
- 关于git pull时出现的问题及解决反思
前因 在前面由于已经git过一次,按照娄老师的要求,代码一个一个commit,所以删掉之前的git仓库(用la查看,使用rm -rf .git删除).但远程origin已经存在,所以执行git rem ...