题目描述
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
输入输出格式
输入格式:
输入文件中仅包含一行两个整数a、b,含义如上所述。
输出格式:
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
输入输出样例
输入样例#1: 复制
1 99
输出样例#1: 复制
9 20 20 20 20 20 20 20 20 20
说明
30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu2602 数字计数
Algorithm:数位DP
************************/
//核心思想:打表?
//好吧我知道为什么过不了了
//数组开小了,访问越界
#include
using namespace std;
const int maxn=15;
typedef long long LL;
LL a,b;
LL cnt[15],ans[5][15],num[5][15];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("count0.in","r",stdin);
}
void init(){
cnt[0]=0;
LL w=1;
for(int i=1;i<=13;++i) cnt[i]=cnt[i-1]*10+w,w*=10;///////////
//cnt[i]表示有 i 位数,各个数字出现的次数
//此处 0 可以在最高位
LL x=a;
if(a==0) num[1][0]=1;
else if(a<0) a=0;//特判a=1或a=0时
while(x){
++num[1][0];
num[1][num[1][0]]=x%10;
x/=10;
}
x=b;
if(b==0) num[2][0]=1;
else if(b<0) b=0;
while(x){
++num[2][0];
num[2][num[2][0]]=x%10;
x/=10;
}
}
void readdata(){
read(a);read(b);
--a;//用 ans[0~b]-ans[0~a-1] 求解
init();
}
void dp(LL r,LL id){
LL t=0,w=1;
for(LL i=1;i<=num[id][0];++i){
t+=num[id][i]*cnt[i-1];
for(LL j=0;j<num[id][i];++j)
ans[id][j]+=w;
ans[id][num[id][i]]+=r%w+1;
w*=10;
}
for(int i=0;i<=9;++i) ans[id][i]+=t;
t=1;
for(int i=1;i<num[id][0];++i){
t*=10;
ans[id][0]-=t;//减去 0 在最高位的情况
}
}
void work(){
dp(a,1);
dp(b,2);
for(int i=0;i<=9;++i){
/*put(ans[2][i]-ans[1][i]);
putchar(' ');*/
printf("%lld ",ans[2][i]-ans[1][i]);
}
}
int main(){
// file();
readdata();
work();
return 0;
}
方法二:
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu2602
Algorithm:数位 DP DFS
************************/
#include
//这道题如果从 0 开始的话还要加个特判
using namespace std;
const int maxn=35;
typedef long long LL;
LL a,b;
LL num[15],dp[20][20];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("count.in","r",stdin);
}
LL dfs(LL dig,int limit,int lead,LL sum,LL pos){
//pos 位数
//dig 要找的数字
//limit 这一位是否有限制
//lead 是否有前导0 如果lead==0 那么有前导0
//sum : 搜到pos位时出现了多少个dig
if(!pos) return sum;
if(!limit && lead && dp[pos][sum]!=-1) return dp[pos][sum];
//没上限且没有前导0
//主要防止0算错 eg.0000 0010
LL ans=0;
int top=limit ? num[pos] : 9;
for(int i=0;i<=top;++i)
ans+=dfs(dig,limit&&i==top,i||lead,sum+((lead||i)&&(i==dig)),pos-1);
if(!limit && lead) dp[pos][sum]=ans;
return ans;
}
LL work(LL dig,LL r){
memset(num,0,sizeof(num));
memset(dp,-1,sizeof(dp));
LL x=r;
if(!x) num[0]=1;
while(x){
++num[0];
num[num[0]]=x%10;
x/=10;
}
return dfs(dig,1,0,0,num[0]);
}
int main(){
// file();
read(a);read(b);
for(LL i=0;i<=9;++i){
put(work(i,b)-work(i,a-1));
putchar(' ');
}
return 0;
}
题目描述
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
输入输出格式
输入格式:
包含两个整数,A B。
输出格式:
一个整数
输入输出样例
输入样例#1: 复制
1 10
输出样例#1: 复制
9
输入样例#2: 复制
25 50
输出样例#2: 复制
20
说明
100%的数据,满足 1 <= A <= B <= 2000000000 。
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu 2657windy
Algorithm:数位DP
************************/
#include
using namespace std;
const int maxn=15;
int a,b,ans[5];
int cnt[15][15],cnt1[15],num[5][15];
//cnt[位数][最高位的数值]=windy数个数
//cnt1[位数]=从0~这个位数的最大值中windy数的个数
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("windy.in","r",stdin);
}
void init(){
cnt[0][0]=1;//初始化,要加0
cnt1[0]=1;
for(int i=0;i<=9;++i) cnt[1][i]=1;
cnt1[1]=10;
for(int l=2;l<=12;++l){
for(int k=0;k<=9;++k){
for(int i=0;i<=9;++i)
if(abs(i-k)>=2) cnt[l][k]+=cnt[l-1][i];//我们把0当做 可以做最高位的数
if(k) cnt1[l]+=cnt[l][k];//不加0,0不做最高位
}
cnt1[l]+=cnt1[l-1];//加上以前位数的个数
}
int x=a;
if(!a) num[1][0]=1;
while(x){
++num[1][0];
num[1][num[1][0]]=x%10;
x/=10;
}
x=b;
if(!b) num[2][0]=1;
while(x){
++num[2][0];
num[2][num[2][0]]=x%10;
x/=10;
}
}
void dp(int r,int id){
num[id][num[id][0]+1]=-100;//防止误把第一位pass掉
ans[id]+=cnt1[num[id][0]-1];
for(int i=num[id][0];i>=1;--i){
if(i==num[id][0]){
for(int j=1;j<num[id][i];++j) ans[id]+=cnt[i][j];
}else {
for(int j=0;j<num[id][i];++j)
if(abs(num[id][i+1]-j)>=2) ans[id]+=cnt[i][j];
if(i==1&&abs(num[id][i+1]-num[id][i])>=2) ans[id]++;//特判 b
}
if(abs(num[id][i+1]-num[id][i])<2) break;//!!如果这一位与上一位相差小于2,直接结束
}
}
void work(){
dp(a,1);
dp(b,2);
printf("%d",ans[2]-ans[1]);
}
int main(){
// file();
read(a);read(b);
--a;
init();
work();
return 0;
}
方法二:
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu2657
Algorithm:数位 DP DFS
************************/
#include
using namespace std;
const int maxn=35;
typedef long long LL;
int a,b;
int num[15],dp[20][20];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("windy.in","r",stdin);
}
int dfs(int pos,int now,int limit,int lead){
if(pos==0) return 1;
if(!limit && lead && dp[pos][now]!=-1) return dp[pos][now];
int ans=0;
int top=limit ? num[pos] : 9;
for(int i=0;i<=top;++i){
if(lead==0||abs(now-i)>=2) ans+=dfs(pos-1,i,limit&&(i==top),lead||i);
}
if(!limit&&lead) dp[pos][now]=ans;
return ans;
}
int work(int r){
memset(num,0,sizeof(num));
// memset(dp,-1,sizeof(dp));
int x=r;
if(!x) num[0]=1;
while(x){
num[0]++;
num[num[0]]=x%10;
x/=10;
}
return dfs(num[0],0,1,0);
}
int main(){
// file();
memset(dp,-1,sizeof(dp));
read(a);read(b);
put(work(b)-work(a-1));
return 0;
}
题目背景
众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
题目描述
话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。 花神的题目是这样的:设 \text{sum}(i)sum(i) 表示 ii 的二进制表示中 11 的个数。给出一个正整数 NN ,花神要问你 \prod_{i=1}^{N}\text{sum}(i)∏
i=1
N
sum(i) ,也就是 \text{sum}(1)\sim\text{sum}(N)sum(1)∼sum(N) 的乘积。
输入输出格式
输入格式:
一个正整数 N。
输出格式:
一个数,答案模 10000007 的值。
输入输出样例
输入样例#1: 复制
3
输出样例#1: 复制
2
说明
对于 100% 的数据,N≤10^15
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu4317
Algorithm:数位 DP
************************/
#include
using namespace std;
const int maxn=1e6+5;
const int mod=1e7+7;
typedef long long LL;
LL n;
LL dp[65][65],num[65],ans[65];
//ans[i]表示 1~N中的含有i个1的数的个数
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("flower.in","r",stdin);
}
LL dfs(int pos,int cnt,int limit,int sum){
//cnt是当前搜到的1的个数
//sum是所需的1的个数
if(!pos) return cnt==sum;
if(!limit && dp[pos][cnt]!=-1) return dp[pos][cnt];
LL tot=0;
int top=limit ? num[pos] : 1;
for(int i=0;i<=top;++i)
tot+=dfs(pos-1,cnt+(i&1),limit&&(i==top),sum);
if(!limit) dp[pos][cnt]=tot;
return tot;
}
LL quickpower(LL i,LL j){
LL anss=1,base=i;
while(j){
if(j&1) anss=anss*base%mod;
base=base*base%mod;//记得及时取模
j>>=1;
}
return anss;
}
void work(){
if(!n) num[0]=1;
while(n){
++num[0];
num[num[0]]=(n&1);
n>>=1;
}
for(int i=1;i<=num[0];++i){
memset(dp,-1,sizeof(dp));
ans[i]=dfs(num[0],0,1,i);
}
LL tot=1;
for(LL i=2;i<=num[0];++i){
tot=tot*quickpower(i,ans[i])%mod;
}
put(tot);
}
int main(){
// file();
read(n);
work();
return 0;
}
题目描述
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少 33 个相邻的相同数字;号码中不能同时出现 88 和 44。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 1111 位数,前不含前导的 00。工具接收两个数 LL 和 RR,自动统计出 [L,R][L,R] 区间内所有满足条件的号码数量。LL 和 RR 也是 1111 位的手机号码。
输入输出格式
输入格式:
输入文件内容只有一行,为空格分隔的 22 个正整数 L,RL,R。
输出格式:
输出文件内容只有一行,为 11 个整数,表示满足条件的手机号数量。
输入输出样例
输入样例#1: 复制
12121284000 12121285550
输出样例#1: 复制
5
说明
样例解释:满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550。
数据范围:10000000000<=L<=R<100000000000 。
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu4214
Algorithm:数位 DP
************************/
#include
using namespace std;
typedef long long LL;
LL L,R;
LL num[25];
LL dp[20][13][11][3][3][3];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("phone.in","r",stdin);
}
LL dfs(int pos,int limit,int judge,int cnt,int mcnt,int now){
if(!pos)
if(mcnt >= 3) return 1;
else return 0;
if(!limit && dp[pos][cnt][now][mcnt>=3][((judge & (1<<4))) == (1<<4)][((judge & (1<<8))) == (1<<8)] != -1)
return dp[pos][cnt][now][mcnt>=3][((judge & (1<<4))) == (1<<4)][((judge & (1<<8))) == (1<<8)];
LL ans = 0;
int top = limit ? num[pos] : 9;
for(int i=0;i<=top;++i){
if(((judge | (1 << i)) & ((1 << 4) | (1 << 8))) == ((1 << 4) | (1 << 8))) continue;
int x = (now == i) ? (cnt + 1) : 1;
ans+=dfs(pos - 1,limit && (i == top),judge | (1 << i),x,max(x,mcnt),i);
}
if(!limit) dp[pos][cnt][now][mcnt>=3][((judge & (1 << 4))) == (1 << 4)][((judge & (1 << 8))) == (1 << 8)] = ans;
return ans;
}
LL work(LL r){
memset(num,0,sizeof(num));
// memset(dp,-1,sizeof(dp));
LL x=r;
while(x){
num[0]++;
num[num[0]] = x % 10;
x /= 10;
}
if(num[0]<=10) num[0]++;//主要防止1000000000减了1之后就少了一位,而这个在算时算了前导0,会出错
return dfs(num[0],1,0,0,0,0);
}
int main(){
// file();
memset(dp,-1,sizeof(dp));
read(L);read(R);
put(work(R) - work(L-1));
return 0;
}
题目描述
你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。
现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0).
输入输出格式
输入格式:
只有1行,为1个整数n.
输出格式:
只有整数,表示N之前出现的数的个数。
输入输出样例
输入样例#1: 复制
1020
输出样例#1: 复制
7
说明
n的长度不超过50,答案不超过2^63-1.
/**************************
User:Mandy.H.Y
Language:c++
Problem:luogu2518
Algorithm:数位DP
**************************/
#include
//删0就相当于把0放在最前面
//所以可以求组合…………
using namespace std;
typedef long long LL;
const int maxn = 35;
char c;
LL num[55],cnt[11],C[66][66];
//C[i][j]是组合数
//cnt[i] 代表num中有cnt[i]个数字i
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar(' '),putch(-x);
else putch(x);
}
void file(){
freopen("count.in","r",stdin);
}
void init(){//组合数,杨辉三角是个好东西
for(int i = 0;i <= 60;++ i) C[i][0] = (LL)1;
for(int i = 1;i <= 60;++ i)
for(int j = 1;j <= 60;++ j)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
void readdata(){
while(~scanf("%c",&c)){
if(!isdigit(c)) continue;
num[0] ++;
num[num[0]] = c ^ 48;
cnt[(c ^ 48)] ++;
}
}
LL dfs(int pos,int limit){
if(pos == num[0] + 1) return 0;//这个数本身不算
LL ans = 1;
if(!limit){
//如果没有限制,那么剩下的数有 num[0] - pos + 1个位置
//因为有重复的数字,如果直接用乘法原理会爆long long,边乘边除太麻烦
//我们可以一组一组放,比如先放cnt[0]个 0,则方案有C[mcnt][cnt[0]]种
//放完0后又放1,则现在还剩下mcnt-cnt[0]个位置,有 C[mcnt-cnt[0]][cnt[1]]种方法
//现在放完0和1,共 C[mcnt][cnt[0]] * C[mcnt-cnt[0]][cnt[1]]种方法
int mcnt = num[0] - pos + 1;
for(int i = 0;i <= 9;++ i){
if(cnt[i]) ans *= C[mcnt][cnt[i]];//有i才放
mcnt-=cnt[i];
}
return ans;
}
ans = 0;
int top = limit ? num[pos] : 9;
for(int i = 0;i <= top;++ i){
if(!cnt[i]) continue;
cnt[i]--;
ans += dfs(pos + 1,limit && i == top);
cnt[i]++;
}
return ans;
}
int main(){
// file();
init();
readdata();
put(dfs(1,1));
return 0;
}
Problem Description
单身!
依然单身!
吉哥依然单身!
DS级码农吉哥依然单身!
所以,他生平最恨情人节,不管是214还是77,他都讨厌!
吉哥观察了214和77这两个数,发现:
2+1+4=7
7+7=72
77=711
最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数!
什么样的数和7有关呢?
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
Input
输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
Output
请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。
Sample Input
3
1 9
10 11
17 17
Sample Output
236
221
0
/************************
User:Mandy.H.Y
Language:c++
Problem:luogu4317
Algorithm:数位 DP
************************/
#include
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
const long long mod=(LL)1e9+7;
LL n,L,R;
LL num[25],power[25];
struct node{
LL cnt,sum,tot;
node(){cnt=-1,sum=0,tot=0;}
node(LL c,LL s,LL t) : cnt(c),sum(s),tot(t){}
}dp[25][10][10];
//dp[位数][当前数%7余数][当前各位之和%7]
//cnt:从1到当前位的与7无关的数的个数
//sum :从1到当前位的与7无关的数的和
//tot :从1到当前位的与7无关的数的平方和
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("test1.in","r",stdin);
}
node dfs(int pos,int limit,int res,int sum){
//res:当前数%7余数
//sum :当前各位之和%7
if(!pos) {
if(sum && res ) return node(1,0,0);
else return node(0,0,0);
}
if( !limit && dp[pos][res][sum].cnt!=-1 ) return dp[pos][res][sum];
LL top=limit ? num[pos] : 9;
node y;
y.cnt=0,y.sum=0,y.tot=0;
for(int i=0;i<=top;++i){
if(i!=7) {//除去含7的数
node x;
x=dfs(pos-1,limit && i==top,(res * 10 + i) % 7,(sum + i) % 7);
LL cur = i * power[pos-1] % mod;
y.cnt=(y.cnt + x.cnt) % mod;
y.sum=(y.sum + cur * x.cnt % mod + x.sum) % mod;
y.tot=((y.tot + x.tot) % mod + cur * cur % mod * x.cnt % mod+ 2 * cur % mod * x.sum % mod/*这里不乘cnt*/) % mod;
//完全平方
}
}
if( !limit ) dp[pos][res][sum]=y;
return y;
}
LL work(LL r){
memset(num,0,sizeof(num));
// memset(dp,-1,sizeof(dp));
LL x=r;
if(!x) num[0]=1;
while(x){
++num[0];
num[num[0]]=x % 10;
x /= 10;
}
node y = dfs(num[0],1,0,0);
return y.tot % mod;
}
int main(){
// file();
read(n);
power[0] = 1;
memset(dp,-1,sizeof(dp));
for(int i = 1;i <= 20;++i) power[i]=(power[i - 1] * 10) % mod;//10的幂
while(n--){
read(L);read(R);
put(((work(R) - work(L - 1))%mod + mod) % mod);
putchar('\n');
}
return 0;
}
Problem Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input
输入的都是整数对n、m(0
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input
1 100
0 0
Sample Output
80
/************************
User:Mandy.H.Y
Language:c++
Problem:hdu2809
Algorithm:数位 DP
************************/
#include
using namespace std;
const int maxn=1e6+5;
int n,m;
int num[20],dp[20][15];
template<class T>inline void read(T &x){
x=0;bool flag=0;char ch=getchar();
while(!isdigit(ch)) flag|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(flag)x=-x;
}
template<class T>void putch(const T x){
if(x>9) putch(x/10);
putchar(x%10|48);
}
template<class T>void put(const T x){
if(x<0) putchar('-'),putch(-x);
else putch(x);
}
void file(){
freopen("62.in","r",stdin);
}
int dfs(int pos,int limit,int now){
if(!pos) return 1;
if(!limit && dp[pos][now]!=-1) return dp[pos][now];
int ans=0;
int top=limit ? num[pos] : 9;
for(int i=0;i<=top;++i){
if(i==4||(now==6&&i==2)) continue;
ans+=dfs(pos-1,limit&&(i==top),i);
}
if(!limit) dp[pos][now]=ans;
return ans;
}
int work(int r){
memset(num,0,sizeof(num));
// memset(dp,-1,sizeof(dp));
int x=r;
if(!x) num[0]=1;
while(x){
num[0]++;
num[num[0]]=x%10;x/=10;
}
return dfs(num[0],1,0);
}
int main(){
// file();
memset(dp,-1,sizeof(dp));
while(scanf("%d%d",&n,&m)){
if((!n)&&(!m)) break;
put(work(m)-work(n-1));
putchar('\n');
}
return 0;
}
【题目描述】
中国人喜欢数字6和8。特别地,一些人喜欢满足含有特定个数6和8的数。现在请求出,在区间[L,R]之间的第K大的含有X个6和Y个8的数。
【输入】
输入的第一行包括4个数字,L,R,X,Y。
接下来的一行给出该组数据的询问数Q。
接下来Q行中,每行有一个整数K。
【输出】
对于某个询问,输出一行,为对应的第K大的数。如果不存在这个数则输出“That’s too bad!”
【输入样例】
1 1000 1 1
10
1
2
3
4
5
6
7
8
9
100
【输出样例】
68
86
168
186
268
286
368
386
468
That’s too bad!
【数据范围】
对于30%的数据,1<=L<=R<=100000
对于100%的数据,1<=L<=R<=10^18
对于100%的数据,1<=X,Y<=18, 1<=Q<=30
/**************************
User:Mandy.H.Y
Language:c++
Problem:mzoj 1486
Algorithm:数位DP
**************************/
//用到了那么一丢丢 恨7不成妻 的思想,不过这道题简单一点
//直接二分求个数再维护最大值即可
#include
using namespace std;
typedef long long LL;
const int maxn = 35;
LL L,R,X,Y,Q,K;
LL num[20],power[21];
struct node{
LL cnt,mans;
node(){cnt = -1;mans = 0;}
node(LL c,LL m) : cnt(c),mans(m){}
}dp[20][20][20];
template<class T>inline void read(T &x){
x = 0;bool flag = 0;char ch = getchar();
while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
if(flag) x = -x;
}
template<class T>void putch(const T x){
if(x > 9) putch(x / 10);
putchar(x % 10 | 48);
}
template<class T>void put(const T x){
if(x < 0) putchar(' '),putch(-x);
else putch(x);
}
void file(){
freopen("0.in","r",stdin);
}
node dfs(int pos,int limit,int six,int eight){
if(!pos) return node((six == X) && (eight == Y),0);
if(!limit && dp[pos][six][eight].cnt != -1) return dp[pos][six][eight];
node ans;
ans.cnt = 0,ans.mans = 0;
LL top = limit ? num[pos] : 9;
for(int i = 0;i <= top;++i){
if(six + (i == 6) > X || eight + (i == 8) > Y) continue;
node x = dfs(pos - 1,limit && (i == top),six + (i == 6),eight + (i == 8));
ans.cnt += x.cnt;
if (x.cnt) ans.mans = max(ans.mans,i * power[pos - 1] + x.mans);
}
if(!limit) dp[pos][six][eight] = ans;
return ans;
}
node work(LL r){//记得开LL啊!!!
memset(num,0,sizeof(num));
// memset(dp,-1,sizeof(dp));
if(!r) num[0] = 1;
while(r){
num[0]++;
num[num[0]] = r % 10;
r /= 10;
}
return dfs(num[0],1,0,0);
}
int main(){
// file();
//memset(dp,-1,sizeof(dp));
power[0] = 1;
for(int i = 1;i <= 19;++i) power[i] = power[i - 1] * 10;
read(L);read(R);read(X);read(Y);
read(Q);
node ansl=work(L - 1);
while(Q--){
read(K);
LL l=L,r=R;
bool judge = 0;
while(l <= r){//二分大法好
LL mid = (l + r) >> 1;
node cur = work(mid);
if(cur.cnt - ansl.cnt == K) {
put(cur.mans);putchar('\n');
judge = 1;break;
}
else {
if(cur.cnt - ansl.cnt < K) l = mid + 1;
else r = mid - 1;
}
}
if(! judge) printf("That's too bad!\n");
}
return 0;
}