博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[COJ0528]BJOI幸运数
阅读量:5286 次
发布时间:2019-06-14

本文共 4123 字,大约阅读时间需要 13 分钟。

[COJ0528]BJOI幸运数

试题描述

输入

见“试题描述

输出

见“试题描述

输入示例

见“试题描述

输出示例

见“试题描述

数据规模及约定

见“试题描述

题解

首先想到一个比较暴力的数位 dp 方法:设 f[i][j][s1][s2] 表示前 i 位中,最高位为 j,其中奇数位的数字和为 s1,偶数位的数字和为 s2,满足这个条件的数的个数。

然而,这样的话每次询问都不得不每位处理时都枚举一下 s1 和 s2,受不了 T = 1000 的数据。

先贴一下这个代码:

#include 
#include
#include
#include
#include
#include
using namespace std;#define LL long longLL 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 110LL 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 
#include
#include
#include
#include
#include
using namespace std;#define LL long longLL 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 101LL 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;}

 

转载于:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6123316.html

你可能感兴趣的文章
对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
查看>>
Thymeleaf模板格式化LocalDatetime时间格式
查看>>
庖丁解“学生信息管理系统”
查看>>
Pyltp使用
查看>>
其他ip无法访问Yii的gii,配置ip就可以
查看>>
php做的一个简易爬虫
查看>>
x的x次幂的值为10,求x的近似值
查看>>
jquery获取html元素的绝对位置和相对位置的方法
查看>>
ios中webservice报文的拼接
查看>>
Power BI 报告的评论服务支持移动设备
查看>>
ACdream 1068
查看>>
HDU 2665 Kth number
查看>>
记叙在人生路上对你影响最大的三位老师
查看>>
002.大数据第二天
查看>>
python装饰器
查看>>
树上的路径
查看>>
问题总结
查看>>
软件随笔
查看>>
Linux下SVN自动更新web [转]
查看>>
Openstack api 学习文档 & restclient使用文档
查看>>