[BZOJ4467] [JSOI2013]数字理论
2016-04-05 16:25
1021 查看
题目相当于要求一个数x,满足:
1. D∗10K−1≤x<D∗10K
2. x mod D=0
3. digit(x)=P //digit(x)是x的各个数位数字之和
4. digit(x/D)=S
考虑进行数位DP
bool dp[len][sum1][sum2][res]意思是,有一个数W,digit(W div D)=sum1,digit(W)=sum2,W mod D=res,能否通过在W的末尾加len位数字使得符合要求
显然边界为dp[0][S][P][0]=1 dp[0][其他]=0
转移为dp[len][sum1][sum2][res]=OR9next=0dp[len−1][sum1+(res∗10+next) div D][sum2+next][(res∗10+next) modD]
找方案时贪心地从高位向地位,在DP数组上爬下去^..^
然而这样状态数是O(K*S*P*D),显然会MLE+TLE
怎么办呢?对!常数优化!
我们可以发现,sum1和res确定时,sum2 mod 9是确定的,于是时间和内存的常数就除了9,然后又有好多无效的状态,如len∗9+sum1<S或len∗9+sum2<P,虽然理论时间复杂度还是O(K*S*P*D*10),大约是90亿,但大多数都是无效状态,拜张爷爷的剪枝技巧所赐,便轻松过去了
1. D∗10K−1≤x<D∗10K
2. x mod D=0
3. digit(x)=P //digit(x)是x的各个数位数字之和
4. digit(x/D)=S
考虑进行数位DP
bool dp[len][sum1][sum2][res]意思是,有一个数W,digit(W div D)=sum1,digit(W)=sum2,W mod D=res,能否通过在W的末尾加len位数字使得符合要求
显然边界为dp[0][S][P][0]=1 dp[0][其他]=0
转移为dp[len][sum1][sum2][res]=OR9next=0dp[len−1][sum1+(res∗10+next) div D][sum2+next][(res∗10+next) modD]
找方案时贪心地从高位向地位,在DP数组上爬下去^..^
然而这样状态数是O(K*S*P*D),显然会MLE+TLE
怎么办呢?对!常数优化!
我们可以发现,sum1和res确定时,sum2 mod 9是确定的,于是时间和内存的常数就除了9,然后又有好多无效的状态,如len∗9+sum1<S或len∗9+sum2<P,虽然理论时间复杂度还是O(K*S*P*D*10),大约是90亿,但大多数都是无效状态,拜张爷爷的剪枝技巧所赐,便轻松过去了
#include <cstdio> #include <assert.h> int K, S, P, D; bool dp[100][901][102][9]; int main() { scanf("%d%d%d%d", &K, &S, &P, &D); if (S > K * 9 || P > K * 9) return puts("-1"), 0; if (S * D % 9 != P % 9) return puts("-1"), 0; dp[0][S][P / 9][0] = 1; for (int i = 1; i < K; i++) { int S_low = S - i * 9, P_low = P - i * 9, MODnine; if (S_low < 0) S_low = 0; if (P_low < 0) P_low = 0; for (int j = S_low; j <= S; j++) { bool (*DP)[9] = dp[i][j]; for (int l = 0; l < D; l++) { MODnine = (j * D + l) % 9; for (int k = P_low / 9, realk = k * 9 + MODnine; realk <= P; k++, realk += 9) for (int di = 0; !DP[k][l] && di < 10; di++) if (dp[i - 1][j + (l * 10 + di) / D][(realk + di) / 9][(l * 10 + di) % D]) DP[k][l] = 1; } } } int head = D; while (head < 10 * D && !dp[K - 1][head / D][(head / 10 + head % 10) / 9][head % D]) head++; if (head == 10 * D) puts("-1"); else { int res = head % D; putchar(head / D + 48); int I = K - 1, J = head / D, K = head / 10 + head % 10, L = head % D, di; int newI, newJ, newK, newL; while (I) { for (di = 0; !dp[I - 1][J + (L * 10 + di) / D][(K + di) / 9][(L * 10 + di) % D]; di++) "Nothing to do.."; putchar((res * 10 + di) / D + 48); res = (res * 10 + di) % D; newI = I - 1, newJ = J + (L * 10 + di) / D, newK = K + di, newL = (L * 10 + di) % D; I = newI, J = newJ, K = newK, L = newL; } assert(res == 0); } return 0; }
相关文章推荐
- JS判断页面首次访问
- JS模拟简易滚动条效果代码(附demo源码)
- JS DOM(文档对象模型)与BOM(浏览器对象模型)
- JS中的forEach、$.each、map方法推荐
- 浏览器环境下Javascript脚本加载与执行探析之DOMContentLoaded
- 推荐13款JavaScript图形和图表绘制工具
- 一 JavaScript之数据类型
- 【笔记】 《js权威指南》- 第13章 浏览器中的JS
- jsp页面跳转传值(变量)
- JS中的window.setTimeout()详解
- JS工程文件结构
- WebAPI请求——js调用
- rem 单位计算javaScript
- jsp的3个编译指令(page,include,taglib)
- NSFileHandle编写json数据格式
- 将key名不带双引号的JSON字符串转换成JSON对象的方法
- javascript异常处理机制
- js遍历jsonTree
- JavaScript的流程控制语句
- 使用JSPatch问题若干及解决方法