有std,但是没有自我实现,所以是无码专区

description

完全由数字组成的字符串 sss,划分成若干段,每一段看成一个十进制的数(允许前导零)求有多少种划分方法使得相邻两个数至少一个是 DDD 的倍数。对 109+710^9+7109+7 取模。

数据:5×105,1065\times 10^5,10^65×105,106 级别。

我的想法

针对 30%30\%30% 的数据:n≤1000n\le 1000n≤1000 【n=∣s∣n=|s|n=∣s∣】。

设 dpi,0/1:dp_{i,0/1}:dpi,0/1​: 划分在 iii 处,枚举上一个划分点 jjj,判断 (j,i](j,i](j,i] 是否是 DDD 的倍数 的方案数。

然后直接转移,就是 O(n2)O(n^2)O(n2) 的。

solution

对于另 20%:(D,10)=120\%:(D,10)=120%:(D,10)=1 就是提示正解的部分分。

记 Si=(∑si⋅10n−i)%DS_i=(\sum_{s_i}·10^{n-i})\%DSi​=(∑si​​⋅10n−i)%D,即以 iii 开始的后缀对应的十进制数(在取模 DDD 的意义下)

判定条件: s[i,j]s[i,j]s[i,j] 组成的数能被 DDD 整除,当且仅当 Si=Sj+1S_{i}=S_{j+1}Si​=Sj+1​。

设 dpi,0/1:dp_{i,0/1}:dpi,0/1​: 从前往后划分到 iii ,当前段能否被 DDD 整除的方案数。

如果能被 DDD 整除,那么必须从 Sj=Si+1,1≤j<iS_j=S_{i+1},1\le j<iSj​=Si+1​,1≤j<i 转移过来,否则从不被整除的 SjS_jSj​ 转移过来。

用一个桶数组 cnti:Sj=icnt_i:S_j=icnti​:Sj​=i 的 dpjdp_jdpj​ 的和。

i.e. 在 iii 转移被整除的信息的时候,相当于去找 cntSicnt_{S_i}cntSi​​ 这个桶,dpi→cntSidp_i\rightarrow cnt_{S_i}dpi​→cntSi​​。

以上是 (D,10)=1(D,10)=1(D,10)=1,当 (D,10)≠1(D,10)\neq 1(D,10)​=1 时,上述的判定条件就不完全对了。

改写 D=D1⋅D2D=D_1·D_2D=D1​⋅D2​,其中 (D1,10)=1,D2=2a5b(D_1,10)=1,D_2=2^a5^b(D1​,10)=1,D2​=2a5b。

改写 Si:S_i:Si​: 从 iii 开始到结尾形成的十进制数对 D1D_1D1​ 取模的结果。

改写判定条件:s[i,j]s[i,j]s[i,j] 组成的数能被 DDD 整除,当且仅当 Si=Sj+1∧D2∣s[i,j]S_i=S_{j+1}\wedge D_2\Big |s[i,j]Si​=Sj+1​∧D2​∣∣∣​s[i,j]。

在十进制下 s[i,j]s[i,j]s[i,j] 要能被 2,52,52,5 的幂次整除,只需要看后面的若干位即可。

这里 D≤106≈220≈59D\le 10^6\approx 2^{20}\approx 5^9D≤106≈220≈59,所以最多看后面的 202020 位。

具体而言

  • 首先判断 s[i−19,i]s[i-19,i]s[i−19,i] 组成的数是否 DDD 的倍数。

    • 是,再从桶里面找 cntSi+1→dpicnt_{S_{i+1}}\rightarrow dp_icntSi+1​​→dpi​。
  • 暴力处理 s[j,i],i−19≤j≤i−1s[j,i],i-19\le j\le i-1s[j,i],i−19≤j≤i−1 判断是否是 DDD 的倍数,再 →dpi\rightarrow dp_i→dpi​ 。
  • 对于 j=i−19j=i-19j=i−19 到 iii 中间已经包含有 202020 位了【i−(i−19)+1=20i-(i-19)+1=20i−(i−19)+1=20】,所以 Sj→cntS_j\rightarrow cntSj​→cnt,可以入桶了。

参考code

#include <bits/stdc++.h>using namespace std;template <typename T>
T power(T a, long long b) {T r = 1;while (b) {if (b & 1) {r *= a;}a *= a;b >>= 1;}return r;
}template <typename T>
T inverse(T a, T m) {a %= m;if (a < 0) {a += m;}T b = m, u = 0, v = 1;while (a) {T t = b / a;b -= a * t;swap(a, b);u -= v * t;swap(u, v);}if (u < 0) {u += m;}return u;
}template <int _P>
struct modnum {static constexpr int P = _P;private:int v;public:modnum() : v(0) {}modnum(long long _v) {v = _v % P;if (v < 0) {v += P;}}explicit operator int() const {return v;}bool operator==(const modnum &o) const {return v == o.v;}bool operator!=(const modnum &o) const {return v != o.v;}modnum inverse() const {return modnum(::inverse(v, P));}modnum operator-() const {return modnum(v ? P - v : 0);}modnum operator+() const {return *this;}modnum &operator++() {v++;if (v == P) {v = 0;}return *this;}modnum &operator--() {if (v == 0) {v = P;}v--;return *this;}modnum operator++(int) {modnum r = *this;++*this;return r;}modnum operator--(int) {modnum r = *this;--*this;return r;}modnum &operator+=(const modnum &o) {v += o.v;if (v >= P) {v -= P;}return *this;}modnum operator+(const modnum &o) const {return modnum(*this) += o;}modnum &operator-=(const modnum &o) {v -= o.v;if (v < 0) {v += P;}return *this;}modnum operator-(const modnum &o) const {return modnum(*this) -= o;}modnum &operator*=(const modnum &o) {v = (int) ((long long) v * o.v % P);return *this;}modnum operator*(const modnum &o) const {return modnum(*this) *= o;}modnum &operator/=(const modnum &o) {return *this *= o.inverse();}modnum operator/(const modnum &o) const {return modnum(*this) /= o;}
};template <int _P>
ostream &operator<<(ostream &out, const modnum<_P> &n) {return out << int(n);
}template <int _P>
istream &operator>>(istream &in, modnum<_P> &n) {long long _v;in >> _v;n = modnum<_P>(_v);return in;
}using num = modnum<1000000007>;int main() {freopen("division.in", "r", stdin);freopen("division.out", "w", stdout);ios::sync_with_stdio(false);cin.tie(0);string s;int d;cin >> s >> d;int e = 1;while (d % 2 == 0) {d /= 2;e *= 2;}while (d % 5 == 0) {d /= 5;e *= 5;}int n = s.size();vector<int> a(n + 1);for (int i = 0; i < n; ++i) {a[i + 1] = (a[i] * 10 + (s[i] - '0')) % (d * e);}int inv10 = d == 1 ? 0 : inverse(10, d);vector<int> pw(n + 1);pw[0] = 1;for (int i = 0; i < n; ++i) {pw[i + 1] = (long long) pw[i] * inv10 % d;}vector<int> base(20);base[0] = 1;for (int i = 0; i + 1 < 20; ++i) {base[i + 1] = base[i] * 10 % (d * e);}vector<num> foo(n + 1), bar(n + 1);vector<num> offset_foo(d), offset_bar(d);bar[0] = 1;num pref = 0;for (int i = 0; i <= n; ++i) {foo[i] += pref;if (a[i] % e == 0) {foo[i] += offset_foo[(long long) a[i] * pw[i] % d];bar[i] += offset_bar[(long long) a[i] * pw[i] % d];}pref += bar[i];offset_foo[(long long) a[i] * pw[i] % d] -= bar[i];offset_bar[(long long) a[i] * pw[i] % d] += foo[i] + bar[i];for (int j = i + 1; j <= n && j < i + 20; ++j) {if ((a[j] - (long long) a[i] * base[j - i]) % (d * e) == 0) {foo[j] -= bar[i];bar[j] += foo[i] + bar[i];}if (a[j] % e == 0 && (long long) a[i] * pw[i] % d == (long long) a[j] * pw[j] % d) {foo[j] += bar[i];bar[j] -= foo[i] + bar[i];}}}cout << foo[n] + bar[n] << "\n";
}

【无码专区2】序列划分(数学)相关推荐

  1. 【无码专区9】序列统计(带权并查集 + 前缀和建边 + dp)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  2. 【无码专区7】括号序列(思维)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  3. 【无码专区6】球与盒子(数学线性筛)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  4. 【无码专区10】第K大查询(双向链表 /主席树+st表)

    已自我实现,但还是归入无码专区序列.哈哈哈哈哈 对于my idea部分,我的每一个想法都实现了,可供参考. problem 给定一个 1∼n1\sim n1∼n 的排列和 kkk,求所有 r−l+1≥ ...

  5. 【无码专区13】最小公倍数(线段树)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 my idea顾名思义,记录了我的整个思维过程,以及自己部分实现细节口胡,还有期望分数 solution才是dls正解,但是因为只 ...

  6. 【无码专区8】三角形二维数点——计数有多少个给定点落在三角形区域内

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

  7. 【无码专区12】子集和(背包dp)

    此题已自我实现,但仍归于无码专区 本题在考场上就过了,所以难度并不高,发现性质即可. problem 有 nnn 个正整数 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,... ...

  8. 【无码专区11】异或2(结论 / 推式子 + 哈希hash + 大整数高精度 加减乘除重载考察)

    本题已自我实现.但仍归于无码专区 problem 求 ∑i=1n−1i⨁(n−i)\sum_{i=1}^{n-1}i\bigoplus (n-i)∑i=1n−1​i⨁(n−i). 20%,n≤1e6; ...

  9. 【无码专区5】01串(大讨论+构造)

    因为只有std,没有自我实现,所以是无码专区 主要是为了训练思维能力 solution才是dls正解,但是因为只有潦草几句,所以大部分会有我自己基于正解上面的算法实现过程,可能选择的算法跟std中dl ...

最新文章

  1. Guava函数式编程
  2. Redis : redis事务
  3. 【转】设置Win32窗口背景颜色
  4. js post中文乱码 php,AJAX之POST数据中文乱码如何解决
  5. SQL之COLLATE 子句 排序规则
  6. DML、DDL、DCL区别
  7. 微信小程序访问豆瓣电影api400错误解决方法
  8. SQL最全基础教程(有本事别看啊!)
  9. 【H3CTE认证和HCIE认证一样吗?】
  10. 自控力lesson14书摘——克服‘紧张症’的法则
  11. 阿里、百度、搜狐等公司社招面试记录与总结
  12. P02014250陈彦菁 信息论
  13. 微风:AI新手入门学习教程
  14. 修改element-plus默认英文为中文
  15. vue路由懒加载resolve方式与import方式
  16. java 文件树百度知道_JAVA百度面试复盘--2020-07-30
  17. k8s本地开发工具telepresence及部署
  18. python 自动登录百度账号 by Dopamine
  19. 如何实现WiFi Display互联:我的一次WiFi Display(Miracast)功能发送端(source)和接收端(sink)的实现笔记
  20. 把Java的nio坑逐个踩一遍

热门文章

  1. 服务器文件每天备份重新命名,定时备份服务器文件至本地电脑
  2. 作业优先调度java代码_如何在触发它时在java代码中为hadoop作业设置优先级?
  3. mysql插入时间区间_mybatis插入数据时返回主键以及MySQL根据时间区间查询问题总结...
  4. linux命令clock,简单了解Linux系统中clock命令的使用方法
  5. 一寸照纯红色底图片_和记场下载
  6. bread是可数还是不可数_雅思官方语法教程之——这个名词到底可不可数?
  7. 电子商务与计算机科学与技术的相关性,电子商务、计算机科学与技术、法学等相关专业。.doc...
  8. java opencsv_用opencsv文件读写CSV文件
  9. java分桃子_猴子分桃子.java
  10. 数据结构——二叉树的非递归算法