Live2D

题解 [HNOI2016]大数

题目传送门

题目大意

给出一个\(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;
}
posted @ 2020-07-24 10:47  Dark_Romance  阅读(114)  评论(0编辑  收藏  举报