何小豆儿在此 发表于 2022-8-9 23:56:11

Atcoder-ABC158-EF 题解

Atcoder题解汇总
ABC 158

E. Divisible Substring (取模前缀和思维, 一点点基本数论)

题意
给了一个长度为 \(n\) 的数字串,和一个质数 \(p\) ,询问有多少子串对应的数字满足是 \(p\) 的倍数,输出答案, 若有前导零也算作合法数字。
数据范围
\(1\leq N \leq 2 * 10^5\)
\(2\leq P \leq 10000\)
思路

[*]显然不能用高精,过于荒谬,然后我就不会了
[*]其实是个前缀和题目,但有个小结论:

[*]\(x_1x_2x_3x_4x_5 * 10^n \% p = m,\;x_1x_2*10^{n+3}\%p=m\)
[*]则 \(x_3x_4x_5 * 10^n \% p = m\), 即 \(x_3x_4x_5 \% p = 0\)
[*]若 \(p\) 是质数,且 \(p \neq 2 \& p \neq 5\)
[*]\(p = 2\), \(p = 5\) 特判即可

[*]利用以上结论做前缀和计数即可,很经典,记得 cnt = 0
Solution
#includetypedef long long ll;typedef unsigned long long ull;typedef std::pair PII;typedef std::pair PLL;typedef double db;#define arr(x) (x).begin(),(x).end()#define x first#define y second#define pb push_back#define endl "\n"using namespace std;/*----------------------------------------------------------------------------------------------------*/ll qmi(ll a, ll k, int mod) {    ll res = 1;    while (k) {            if (k & 1)                  res = res * a % mod;            a = a * a % mod;            k >>= 1;    }    return res;}int main() {    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int n, p;    string s;    cin >> n >> p >> s;    ll sum = 0, ans = 0;    vector cnt(p, 0);    if (p == 2 || p == 5) {      for (int i = n - 1; i >= 0; i--)            ans = ans + ((s - '0') % p == 0) * (i + 1);    }    else {      cnt = 1;      for (int i = 0; i < n; i++) {            sum = (sum * 10 + s - '0') % p;            ll now = qmi(10, n - 1 - i, p) * sum % p;            ans += cnt;            cnt++;      }    }    coutn;    vector v(n + 1);    for (int i = 1; i > v.x >> v.y;      v.y += v.x;    }    sort(v.begin() + 1, v.end());    vector f(n + 2, 0);   // f 代表 的方案数。主动激活由 right 转移, 不激活由 i + 1 转移    f = 1;    vector stk(n + 2, 0);    int top = 0;    stk[++top] = n + 1;    v.pb({2e9 + 10 ,0});    for (int i = n; i ; i--) {      while (top && v].x < v.y) top--;      int right = max(stk, i);      stk[++top] = i;      f = (f + f) % mod;    }    cout
页: [1]
查看完整版本: Atcoder-ABC158-EF 题解