[COJ0528]BJOI幸运数
[COJ0528]BJOI幸运数
试题描述
输入
见“试题描述”
输出
见“试题描述”
输入示例
见“试题描述”
输出示例
见“试题描述”
数据规模及约定
见“试题描述”
题解
首先想到一个比较暴力的数位 dp 方法:设 f[i][j][s1][s2] 表示前 i 位中,最高位为 j,其中奇数位的数字和为 s1,偶数位的数字和为 s2,满足这个条件的数的个数。
然而,这样的话每次询问都不得不每位处理时都枚举一下 s1 和 s2,受不了 T = 1000 的数据。
先贴一下这个代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define LL long long LL read() {
LL x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 20
#define maxs 90
#define maxk 110
LL g[maxn][10][maxs][maxs];
int Gcd[maxs][maxs]; int gcd(int x, int y) { return !y ? x : gcd(y, x % y); } int K, num[maxn];
LL sum(LL x) {
int cnt = 0; LL tx = x;
while(x) num[++cnt] = x % 10, x /= 10;
LL ans = 0;
int s1 = 0, s2 = 0;
for(int i = cnt; i; i--) {
for(int j = 0; j < num[i]; j++)
for(int t1 = max(s1, 1); t1 < maxs; t1++)
for(int t2 = max(s2, 1); t2 < maxs; t2++)
if(Gcd[t1][t2] <= K && g[i][j][t1-s1][t2-s2]) {
ans += g[i][j][t1-s1][t2-s2];
// printf("%d %d %d %d: %d\n", i, j, t1-s1, t2-s2, g[i][j][t1-s1][t2-s2]);
}
if(i & 1) s1 += num[i]; else s2 += num[i];
}
if(Gcd[s1][s2] <= K && s1 && s2) ans++;
// printf("%lld: %lld\n", tx, ans);
return ans;
} int main() {
g[0][0][0][0] = 1;
for(int i = 0; i < maxn - 1; i++)
for(int j = 0; j <= 9; j++)
for(int s1 = 0; s1 < maxs; s1++)
for(int s2 = 0; s2 < maxs; s2++)
if(g[i][j][s1][s2]) {
for(int k = 0; k <= 9; k++) {
int S1 = s1, S2 = s2;
if(i + 1 & 1) S1 += k; else S2 += k;
g[i+1][k][S1][S2] += g[i][j][s1][s2];
}
// printf("%d %d %d %d: %d\n", i, j, s1, s2, g[i][j][s1][s2]);
}
for(int i = 0; i < maxs; i++)
for(int j = 0; j < maxs; j++)
Gcd[i][j] = gcd(i, j); int T = read();
while(T--) {
K = read(); LL l = read(), r = read();
printf("%lld\n", sum(r) - sum(l - 1));
} return 0;
}
对了记得预处理 Gcd[i][j],否则会更慢。。。
现在我们主要目的是优化每次询问所消耗的代价,核心在于不能再每次枚举 s1 和 s2 了。
我们考虑一下求 [1, x] 中答案的过程,我们是一位位确定数字的,所以当前状态可以形象地表示为一下形式:
XXXX____
其中“X”表示已填数字,“_”表示未填数字,我们发现刚才之所以要枚举 s1 和 s2 的原因在于前面填了数字之后,奇偶位上已经有一定的数字和了,所以在这里我们不妨将其设为状态,于是就变成了:
f[i][k][s1][s2] 表示还有 i 位未填,且前面已经填写的数字中,奇数位上数字和为 s1,偶数位上数字和为 s2,现在我们要填满后面那 i 个空位,并且满足填完之后整个数奇数位之和与偶数位之和的最大公约数不超过 k,那么满足上面这一系列条件的填法有多少种。
显然初始状态 f[0][1~maxk][1~maxs][1~maxs] = 1,其中 maxk 表示输入的 k 的最大值,maxs 表示可能出现的最大数字和;
转移:
1. f[i][k][s1][s2] -> f[i+1][k][s1+j][s2] (0 ≤ j < 10),i+1 为奇数
2. f[i][k][s1][s2] -> f[i+1][k][s1][s2+j] (0 ≤ j < 10),i+1 为偶数
这样询问的负担就减轻不少了。
这题还得卡卡常数。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define LL long long LL read() {
LL x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 19
#define maxs 90
#define maxk 101
LL f[maxn][maxk][maxs][maxs];
int Gcd[maxs][maxs]; int gcd(int x, int y) { return !y ? x : gcd(y, x % y); } int num[maxn];
LL sum(LL x, int k) {
int cnt = 0;
while(x) num[++cnt] = x % 10, x /= 10;
int s1 = 0, s2 = 0;
LL ans = 0;
for(int i = cnt; i; i--) {
for(int j = 0; j < num[i]; j++) {
ans += f[i-1][k][s1][s2];
if(i & 1) s1++; else s2++;
}
}
ans += f[0][k][s1][s2];
return ans;
} int main() {
for(int i = 0; i < maxs; i++)
for(int j = 0; j < maxs; j++) Gcd[i][j] = gcd(i, j);
for(int k = 1; k < maxk; k++)
for(int i = 1; i < maxs; i++)
for(int j = 1; j < maxs; j++)
if(Gcd[i][j] <= k) f[0][k][i][j]++;
for(int i = 0; i < maxn - 1; i++)
for(int k = 1; k < maxk; k++) {
int mxs = (maxn - i >> 1) * 9;
for(int s1 = 0; s1 <= mxs; s1++)
for(int s2 = 0; s2 <= mxs; s2++) if(f[i][k][s1][s2])
for(int j = 0; j <= 9; j++) {
int t1 = s1, t2 = s2;
if(i + 1 & 1) t1 -= j; else t2 -= j;
if(t1 < 0 || t2 < 0) break;
f[i+1][k][t1][t2] += f[i][k][s1][s2];
}
} int T = read();
while(T--) {
int k = read(); LL l = read(), r = read();
printf("%lld\n", sum(r, k) - sum(l - 1, k));
} return 0;
}
[COJ0528]BJOI幸运数的更多相关文章
- 京东2017校园招聘笔试题 【第K个幸运数】
题目描述 4和7是两个幸运数字,我们定义,十进制表示中,每一位只有4和7两个数的正整数都是幸运数字. 前几个幸运数字为:4,7,44,47,74,77,444,447... 现在输入一个数字K,输出第 ...
- [51NOD1230]幸运数(数位DP)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1230 dp(l,s,ss)表示长度为l的数各位和为s,各位平方 ...
- Problem 1007 幸运数 线段树成段更新
题目链接: 题目 Problem 1007 幸运数 Time Limit: 2000 mSec Memory Limit : 131072 KB 问题描述 皮特的幸运数是2和5.只由幸运数字2和5组成 ...
- pongo英雄会-幸运数题解
显然我们只要知道1~x范围有多少幸运数(用f(x)表示),lucky(x,y)=f(y)-f(x-1). 解法1. 计算排列数 由于y<=1000000000这个规模,我们不能暴力验证每个数是否 ...
- Python 计算当真因子个数为偶数个时为幸运数,计算区间内幸运数之和
晚饭后朋友发来个问题,正好无事做,动手写了一下 若一个正整数有偶数个不同的真因子,则称该数为幸运数.如4含有2个真因子为 1 和 2 .故4是幸运数.求[2,100]之间的全部幸运数之和. 常规思路 ...
- 蓝桥杯 历届试题 幸运数 dfs
历届试题 幸运数 时间限制:1.0s 内存限制:256.0MB 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的"筛法"生成 . 首先从1开始写出自然数1,2, ...
- C. cltt的幸运数LCAtarjan
/*C: cltt的幸运数 Time Limit: 1 s Memory Limit: 128 MB Submit Problem Description 一棵树有n个节点,共m次查询,查询 ...
- C. cltt的幸运数LCAdfs
/*C: cltt的幸运数 Time Limit: 1 s Memory Limit: 128 MB Submit Problem Description 一棵树有n个节点,共m次查询,查询 ...
- [蓝桥杯]PREV-10.历届试题_幸运数
问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的“筛法”生成 . 首先从1开始写出自然数1,,,,,,.... 就是第一个幸运数. 我们从2这个数开始.把所有序号能被2整除的项删除,变 ...
随机推荐
- Notepad++ 开启「切分窗口」同时检视、比对两份文件
Notepad++ 是个相当好用的免费纯文本编辑器,除了内建的功能相当多之外,也支持外挂模块的方式扩充各方面的应用.以前我都用 UltraEdit 跟 Emeditor,后来都改用免费的 Notepa ...
- php 简单分页类
/** file: page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 privat ...
- python--文件删除、判断目录存在、字符串替换
昨晚笔试了金山WPS的测试开发卷,做个笔记(但不是答案,只是我的想法),关于文件和字符串的处理正在写入与完善至上一篇的博客中,现在题目如下: 1.使用脚本语言删除E:\abc目录下的所有文件: 利用o ...
- python学习笔记-(一)初识python
1.python的前世今生 想要充分的了解一个人,无外乎首先充分了解他的过去和现在:咱们学习语言也是一样的套路 1.1 python的历史 Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈp ...
- URL组分
url通常包含多个组成部分,在js中可通过location对象获取其中各项信息 访问http://mp.weixin.qq.com/s?__biz=MjM5NjA0NjgyMA==&mid=2 ...
- OC-Q&A
How to declare a string in Objective-C ? A C string is just like in C. char myCString[] = "test ...
- php.ini中有关安全的设置
php的默认配置文件在 /usr/local/apache2/conf/php.ini,通过为了使你的web更安全,我们需要对php.ini进行一些设置! (1) 打开php的安全模式 php的安全模 ...
- 浅谈JavaScript中的事件
引言 Html页面与JavaScript之间的交互是通过事件来完成的.事件,就是文档或者浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(处理程序)来预订事件,以便事件发生时执行相应的代码.这在传 ...
- MVC下的客户端模板技术
1.引言 在Web编程中,我们有时经常需要使用Ajax来访问服务端的接口,然后使用这些返回的数据(一般格式都是JSON)来展示客户端的相关信息.例如:在一个商品列表,我们点击某一样的商品,查看该商品的 ...
- apt-get 与 yum的区别 (转)
一般来说著名的linux系统基本上分两大类:1.RedHat系列:Redhat.Centos.Fedora等2.Debian系列:Debian.Ubuntu等 RedHat 系列 1 常见的安装包格式 ...