題解 [HNOI2016]大數
阿新 • • 發佈:2020-07-24
題目大意
給出一個\(n\)個數的字串,有\(m\)次查詢,對於該串的子串\([l,r]\)有多少個子串滿足是固定素數\(p\)的倍數。
思路
其實很簡單,但是一開始想偏了。。。果然還是自己菜啊。。。
我們可以想到統計一下字尾和\(s[i]\),表示\([i,n]\)構成的數,那麼,判斷一個區間\([l,r]\)是不是\(p\)的倍數就等價於:
\[\dfrac{s[l]-s[r+1]}{10^{n-r}}\equiv 0 \pmod p \]
我們發現如果\(\gcd(10,p)=1\)的話,分母就不會產生影響,於是判斷條件就是:
\[s[l]\equiv s[r+1]\pmod p \]
於是對於這種情況我們就可以用莫隊\(\Theta(n\sqrt n)\)開桶記錄答案。
如果\(\gcd(10,p)\not=1\)的話,那麼\(p=2 \operatorname{or} 5\),我們發現這種情況對於區間\([l,r]\)判斷是否的話直接判斷第\(r\)位是不是\(2\operatorname{or}5\)的倍數即可。於是我們可以\(\Theta(n)\)解決這種情況。
果然還是自己菜了啊。。。這都沒有看出來。。。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define ll long long #define MAXN 200005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} char S[MAXN]; ll sum,ans[MAXN];int n,m,p,un,s[MAXN],tmp[MAXN],bel[MAXN],cnt[MAXN]; namespace Subtask1{ struct node{ int l,r,id; bool operator < (const node &p)const{return bel[l] != bel[p.l] ? l < p.l : r < p.r;} }q[MAXN]; void cge (int x,int k){sum -= 1ll * cnt[x] * (cnt[x] - 1) / 2,cnt[x] += k,sum += 1ll * cnt[x] * (cnt[x] - 1) / 2;} void Work (){ int siz = sqrt (n); for (Int i = n,c = 1;i;-- i,c = 1ll * c * 10 % p) s[i] = (s[i + 1] + 1ll * c * (S[i] - '0') % p) % p,bel[i] = (i - 1) / siz + 1,tmp[i] = s[i]; sort (tmp + 1,tmp + n + 2);un = unique (tmp + 1,tmp + n + 2) - tmp - 1;for (Int i = 1;i <= n + 1;++ i) s[i] = lower_bound (tmp + 1,tmp + un + 1,s[i]) - tmp; read (m);for (Int i = 1;i <= m;++ i) read (q[i].l,q[i].r),q[i].r ++,q[i].id = i;sort (q + 1,q + m + 1);int l = 1,r = 0; for (Int i = 1;i <= m;++ i){ while (l < q[i].l) cge (s[l ++],-1);while (l > q[i].l) cge (s[-- l],1); while (r < q[i].r) cge (s[++ r],1);while (r > q[i].r) cge (s[r --],-1); ans[q[i].id] = sum; } for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n'); return ; } } namespace Subtask2{ int snum[MAXN];ll ssum[MAXN]; void Work(){ for (Int i = 1;i <= n;++ i){ snum[i] = ((S[i] - '0') % p == 0); ssum[i] = ssum[i - 1] + 1ll * ((S[i] - '0') % p == 0) * i; } read (m); while (m --){ int l,r;read (l,r); write (ssum[r] - ssum[l - 1] - (snum[r] - snum[l - 1]) * (l - 1)),putchar ('\n'); } } } signed main(){ read (p),scanf("%s",S + 1),n = strlen (S + 1); if (p == 2 || p == 5) Subtask2::Work (); else Subtask1::Work (); return 0; }