文章目录

  • 题意
  • 思路
  • 注意
  • 代码

题意

有一个长度为n(n≤5∗104)n(n\le 5*10^4)n(n≤5∗104)的只包含数字和?的字符串sss,?中可以填上任意数字。一种合法的填数方案必须满足,一个长度为m(m≤20)m(m\le 20)m(m≤20)的ttt是sss的子串(必须连续)。

把所有合法的方案看成10进制数,有q(q≤105)q(q\le 10^5)q(q≤105)个询问,每次询问求第k(k≤1018)k(k\le 10^{18})k(k≤1018)小的数对109+710^9+7109+7取模。

思路

容易想到数位DP。

dp[i][j]dp[i][j]dp[i][j]表示sss的前i−1i-1i−1位已经确定,第iii到nnn位待定,已经匹配了ttt的前j−1j-1j−1位的合法填数方案数。特别的,当j=m+1j=m+1j=m+1时表示已经匹配了一个ttt,在接下来填数的过程中无需考虑ttt为子串的限制。

在询问中从高位到低位依次枚举sss的每一个?位填什么。对于每一位,从0到9枚举,假如枚举这一位是iii,而kkk大于这一位放iii的方案数,就不可能走iii,把这种情况的方案数减掉,继续枚举,直到kkk小于等于这位放jjj的方案数,就给这一位填上jjj,枚举下一位。单次询问O(n)O(n)O(n)。

这样能够得到50分的好成绩。

上述做法处理询问太过缓慢,要想办法优化。然后就是题解思路了。。。

把每个dp[i][j]dp[i][j]dp[i][j]的状态看成一个点,状态转移看成一条单向边,那么整个DP的过程就可以看成是一张DAG。考虑重链剖分喵喵喵,假如一个点有多条连边,就选DP值最大的那个作为重儿子。可以像树上重链剖分一样说明,只要跳一次轻链,跳到的节点包含的合法方案数至少是当前的2倍。在重链上倍增,设r[i][j][w]r[i][j][w]r[i][j][w]表示从dp[i][j]dp[i][j]dp[i][j]这个状态,沿着重儿子跳2w2^w2w步能跳到的地方,顺便再记一下跳这么多步之后kkk需要减掉的值(参考上面的O(n)O(n)O(n)做法),再记一下这其中选的数对答案的贡献。

可以发现单次询问的复杂度变成了O(log⁡klog⁡n)O(\log k \log n)O(logklogn),log⁡k\log klogk是链的条数,log⁡n\log nlogn是重链上倍增,那就可以过此题了。

注意

方案数可能非常大,但是由于询问只有101810^{18}1018,所以方案数大于101810^{18}1018的都赋值成1018+110^{18}+11018+1。

然后为了防止链剖的O(log⁡k)O(\log k)O(logk)退化成O(log⁡方案数)O(\log 方案数)O(log方案数),在儿子的方案数都是101810^{18}1018的时候,选当前位放的iii最小的那个。

代码

solve1()(50分)作为参考来看solve2()(优化后)就非常清晰了。

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
#define fi first
#define se second
#define mp make_pair
typedef long long LL;
const LL inf = 1e18;
const int N = 5e4 + 10, M = 20 + 5, E = 20;
const int mod = 1e9 + 7;
int T, n, m, q, to[M][10], po[N], val[N], sum, w[N][M][E];
pii r[N][M][E];
LL f[N][M], g[N], h[N][M][E];
char s[N], t[M];int fail[N];
void KMP()
{fail[1] = 0;for (int i = 2; i <= m; ++ i){int j = fail[i-1];while (j && t[j + 1] != t[i]) j = fail[j];if (t[j + 1] == t[i]) fail[i] = j + 1;else fail[i] = 0;}for (int i = 1; i <= m; ++ i)for (int j = 0; j <= 9; ++ j){if (j == t[i] - '0') to[i][j] = i + 1;else if (i == 1) to[i][j] = 1;else to[i][j] = to[fail[i-1]+1][j];}for (int i = 0; i <= 9; ++ i)to[m+1][i] = m+1;
}LL dfs(int u, int v)
{if (f[u][v] != -1) return f[u][v];if (u > n) return f[u][v] = v > m;if (s[u] == '?'){f[u][v] = 0;for (int i = 0; i <= 9; ++ i){ // 不特判f[u][v] += dfs(u + 1, to[v][i]);if (f[u][v] > inf) f[u][v] = inf + 1;}}else f[u][v] = dfs(u + 1, to[v][s[u] - '0']);return f[u][v];
}void init()
{po[n] = 1;for (int i = n-1; i >= 1; -- i)po[i] = 10LL * po[i + 1] % mod;for (int i = 1; i <= n; ++ i)if (s[i] != '?')val[i] = 1LL * po[i] * (s[i] - '0') % mod;memset(f, -1, sizeof(f));
}int solve1(LL k) // 50 pts
{if (k > f[1][1] || f[1][1] == 0) return -1;int v = 1, ans = 0;for (int u = 1; u <= n; ++ u){if (s[u] == '?'){for (int i = 0; i <= 9; ++ i){ // 大家好像都没有特判开头的0,那我也不判了。。。if (f[u + 1][to[v][i]] < k)k -= f[u + 1][to[v][i]];else{v = to[v][i];(ans += 1LL * i * po[u] % mod) %= mod;break;}}}else{v = to[v][s[u] - '0'];(ans += val[u]) %= mod;}}return ans;
}void init2()
{memset(r, 0, sizeof(r));memset(h, 0, sizeof(h));memset(w, 0, sizeof(w));for (int u = n; u >= 1; -- u)for (int v = m+1; v >= 1; -- v){if (f[u][v] == -1) f[u][v] = 0;if (s[u] != '?'){r[u][v][0] = mp(u + 1, to[v][s[u]-'0']);h[u][v][0] = 0;w[u][v][0] = 1LL * (s[u] - '0') * po[u] % mod;}else{LL now = 0;for (int i = 0; i <= 9; ++ i){if (f[u + 1][to[v][i]] > h[u][v][0]){r[u][v][0] = mp(u + 1, to[v][i]);h[u][v][0] = now;w[u][v][0] = 1LL * i * po[u] % mod;}now += f[u + 1][to[v][i]];if (now > inf) break;}}for (int i = 1; i < E; ++ i){r[u][v][i] = r[r[u][v][i-1].fi][r[u][v][i-1].se][i-1];h[u][v][i] = h[u][v][i-1] + h[r[u][v][i-1].fi][r[u][v][i-1].se][i-1];if (h[u][v][i] > inf) h[u][v][i] = inf + 1;w[u][v][i] = (w[u][v][i-1] + w[r[u][v][i-1].fi][r[u][v][i-1].se][i-1]) % mod;if (r[u][v][i].fi == 0) h[u][v][i] = inf + 1;}}
}int solve2(LL k)
{if (k > f[1][1] || f[1][1] == 0) return -1;int u = 1, v = 1, ans = 0;
//  int NNN = 0;while (u <= n){for (int i = E-1; i >= 0; -- i){int nu = r[u][v][i].fi;int nv = r[u][v][i].se;if (h[u][v][i] < k && h[u][v][i] + f[nu][nv] >= k){(ans += w[u][v][i]) %= mod;k -= h[u][v][i];u = nu; v = nv;}}if (u > n) break;if (s[u] == '?'){for (int i = 0; i <= 9; ++ i){if (f[u + 1][to[v][i]] < k)k -= f[u + 1][to[v][i]];else{v = to[v][i];(ans += 1LL * i * po[u] % mod) %= mod;break;}}}else{if (v <= m) v = to[v][s[u] - '0'];(ans += val[u]) %= mod;}u++;}return ans;
}int main()
{for (scanf("%d", &T); T--; ){scanf("%d%d", &n, &q);scanf("%s%s", t + 1, s + 1);m = strlen(t + 1);KMP();init();dfs(1, 1);init2();for (; q--; ){LL k;scanf("%lld", &k);printf("%d\n", solve2(k));}}return 0;
}
/*
1
6 1
133
?6??3?
6*/

【香蕉oi】耍望节(数位DP+倍增优化)相关推荐

  1. Codeforces Beta Round #51 D. Beautiful numbers 数位dp + 状态优化

    传送门 文章目录 题意: 思路: 题意: 思路: 数位dpdpdp挺经典的一个题辣,有一个很明显的状态就是f[pos][num][lcm]f[pos][num][lcm]f[pos][num][lcm ...

  2. 数位dp 的简单入门

    时间紧张,就不讲那么详细了. 之前一直被深搜代码误解,以为数位dp 其实就是记忆化深搜...(虽说爆搜确实很舒服而且还好想) 但是后来发现数位dp 的标准格式其实是 预处理 + dp ...... 数 ...

  3. 数位DP - 带3的数

    目录 题目来源 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目来源 数位DP_哔哩哔哩_bilibili 题目描述 求区间[L,R]范围内有多少带3的数. 所谓带3的数就是这个数的十进制 ...

  4. 【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)

    1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MB Submit: 2774  Solved: 1230 [Submit ...

  5. 不要62 ---数位DP

    题意:求m到n中不含62和4的数的个数. 题目链接 思路:数位dp模板求满足的数字或不满足的数字,刚学,就求不满足的数. #include<stdio.h> #include<str ...

  6. bzoj 3598 [ Scoi 2014 ] 方伯伯的商场之旅 ——数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3598 数位DP...东看西看:http://www.cnblogs.com/Artanis/ ...

  7. cojs 简单的数位DP 题解报告

    首先这道题真的是个数位DP 我们考虑所有的限制: 首先第六个限制和第二个限制是重复的,保留第二个限制即可 第五个限制在转移中可以判断,不用放在状态里 对于第一个限制,我们可以增加一维表示余数即可 对于 ...

  8. 数位DP 不断学习中。。。。

    1, HDU 2089  不要62 :http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:不能出现4,或者相邻的62, dp[i][0],表示不存在不吉 ...

  9. [数位dp] spoj 10738 Ra-One Numbers

    题意:给定x.y.为[x,y]之间有多少个数的偶数位和减去奇数位和等于一. 个位是第一位. 样例: 10=1-0=1 所以10是这种数 思路:数位dp[i][sum][ok] i位和为sum 是否含有 ...

最新文章

  1. locks java_java中Locks的使用
  2. 通信网络基础期末复习-第四章-多址接入协议
  3. IIS日志分析方法及工具
  4. SAP CX Upscale Commerce : SAP全新推出的电商云平台
  5. 数据库技术基础:数据库与数据库管理系统概念介绍
  6. 6-第三方库离线安装法
  7. CentOS6实现路由器功能
  8. 实践 | 在MySql中,这四种方法可以避免重复插入数据!
  9. h5 uniapp history模式下刷新页面404
  10. “十四五”国家重点研发计划“区块链”重点专项 2022年(附pdf下载地址)
  11. 什么是webpack? ----(webpack入门)
  12. winform直接控制云台_售价899元,大疆手机云台DJI OM 4发布,磁吸式卡位 15小时续航...
  13. uni-app运行到微信开发工具无法预览
  14. MDCC2013会议笔记
  15. 9月,重磅推出Linux、数据结构、领域驱动等10本程序员新书
  16. 李飞飞团队造出“窥视未来”新AI:去哪干啥一起猜,准确率压倒老前辈
  17. oracle中alter index,oracle alter index rebuild online和alter index rebuild的區別
  18. 骁龙780G和骁龙768G参数对比 骁龙780G和骁龙768G差距大不大
  19. 符号拓展指令CBW、CWD、CDQ、CWDE、CDQE
  20. PCB抄板过程中反推原理图的方法

热门文章

  1. 解决linux无法启动,进入救援模式也报错:you don‘t have any linux partitions的问题
  2. 哈工大软件过程与工具复习总结
  3. PS唯美清新花朵调色
  4. 1. 英文SCI论文引言写作四步走模型学习笔记
  5. SCANDY让你的手机变成扫描仪
  6. 【PBL项目实战】户外智慧农场项目实战系列之4——Mind+Mixly双平台ESP32数据上云及云端可视化实时展示
  7. 企业邮箱托管选哪家好,163企业邮箱如何购买?
  8. 【Vue3从零开始-实战】S14:详情页回退事件及路由参数的传递获取数据
  9. 千里马 android framework之MotionEvent.ACTION_CANCEL怎么产生-讨厌的android触摸面试题
  10. http协议解决粘包拆包半包 的编码解码过程、 以及netty 使用http协议的原理