BZOJ4542 [HNOI2016] 大数

【问题描述】

小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345

。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也

是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素

数7的倍数。

【输入格式】

第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的

子串S[fr…to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1…3]为 2

13。N,M<=100000,P为素数

【输出格式】

输出M行,每行一个整数,第 i行是第 i个询问的答案。

【输入样例】

11

121121

3

1 6

1 5

1 4

【输出样例】

5

3

2

【样例解释】

第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。

【数据规模】

N,M<=100000

正解:莫队算法+特判

 1 #include <iostream>
 2 #include <iomanip>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <string>
 8 #include <cstring>
 9 #include <map>
10 #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
11 #define RG register
12 #define ull unsigned long long
13 const int N = 150000;
14
15 using namespace std;
16
17 map <ull,ull> Map;
18
19 ull gi(){
20     char ch=getchar();ull x=0;
21     while(ch<‘0‘ || ch>‘9‘)ch=getchar();
22     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘;ch=getchar();}
23     return x;
24 }
25
26 char ch[N];
27 ull yu[N],rt[N],jl[N],da[N],xh[N],sum[N];
28 ull sq;
29
30 struct date{
31     int l,r,i;
32     bool operator < (const date &a) const{
33         if (a.l/sq==l/sq) return a.r>r;
34         return a.l/sq>l/sq;
35     }
36 }f[N],t[N];
37
38 bool cmp(const date &a,const date &b){
39     if (a.r==b.r) return a.l<b.l;
40     return a.r<b.r;
41 }
42
43 void put(ull x)
44 {
45     int num = 0; char c[20];
46     while(x) c[++num] = (x%10)+48, x /= 10;
47     while(num) putchar(c[num--]);
48     putchar(‘\n‘);
49 }
50
51 int main(){
52     File("number");
53     ull p=gi();scanf("%s",ch);
54     int q=gi();RG int i,l,r;ull ans=0;ull j;
55     int h=strlen(ch);sq=sqrt(h*1.0);
56     for (i=1; i<=q; i++) f[i]=(date){gi(),gi(),i};
57     if (p!=2 && p!=5){
58         for (i=1; i<=q; i++) f[i].r++;
59         j=1;yu[h+1]=0;
60         for (i=h-1; i>=0; i--){
61             j=j*10%p;
62             rt[i+1]=yu[i+1]=(yu[i+2]+(ch[i]-‘0‘)*j)%p;
63         }h++;
64         sort(rt+1,rt+h+1);
65         sort(f+1,f+q+1);
66         for (i=1; i<=h; i++) Map[rt[i]]=i;
67         for (i=1; i<=h; i++) yu[i]=Map[yu[i]];
68         l=f[1].l,r=l-1;ans=0;
69         for (i=1; i<=q; i++){
70             while(l>f[i].l) ans+=jl[yu[--l]]++;
71             while(r<f[i].r) ans+=jl[yu[++r]]++;
72             while(l<f[i].l) ans-=--jl[yu[l++]];
73             while(r>f[i].r) ans-=--jl[yu[r--]];
74             da[f[i].i]=ans;
75         }
76     }else{
77             for (i=1; i<=h; i++){
78                 yu[i]=(ch[i-1]-‘0‘)%p;
79                 xh[i]=xh[i-1]+(yu[i]==0?1:0);
80                 sum[i]=sum[i-1]+(yu[i]==0?i:0);
81             }
82             for (i=1; i<=q; i++)
83                 da[i]=sum[f[i].r]-sum[f[i].l-1]-(f[i].l-1)*(xh[f[i].r]-xh[f[i].l-1]);
84         }
85     for (i=1; i<=q; i++)
86             if (da[i]) put(da[i]);
87             else printf("0\n");
88         return 0;
89 }
时间: 2024-10-01 16:22:33

BZOJ4542 [HNOI2016] 大数的相关文章

[BZOJ4542] [Hnoi2016] 大数 (莫队)

Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007:显然0077的子串007有6个子串都是素数7的倍数. Input 第一行一个整数:P.第二行一个串:S.第三行一个整数:M.接下来M行,每行两个整数

bzoj4542: [Hnoi2016]大数(莫队)

这题...离散化...$N$和$n$搞错了...查了$2h$...QAQ 考虑$s[l...r]$,可以由两个后缀$suf[l]-suf[r+1]$得到$s[l...r]$代表的数乘$10^k$得到的结果,如果$p$不为$2$或$5$,即$gcd(p, 10^k)=1$,那么显然$s[l...r]$乘$10^k$模$p$为$0$的话,$s[l...r]$模p也为$0$,所以我们就可以变成询问$[l,r+1]$里有几个相同的后缀了. 如果$p$为$2$或$5$的话,我们还得判断这个数的个位是否是$

【莫队】bzoj4542: [Hnoi2016]大数

挺有意思的,可以仔细体味一下的题:看白了就是莫队板子. Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007:显然0077的子串007有6个子串都是素数7的倍数. Input 第一行一个整数:P.第二行

【BZOJ4542】[Hnoi2016]大数 莫队

[BZOJ4542][Hnoi2016]大数 Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345.小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数).例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007:显然0077的子串007有6个子串都是素数7的倍数. Input 第一行一个整数:P.第二行一个串:S

【bzoj4542】[Hnoi2016]大数

1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 9 typedef long long LL; 10 11 #define N 100010 12 13 struct Node 14 { 15 L

[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)

正经题解在最下面 http://blog.csdn.net/qq_32739495/article/details/51286548 写的时候看了大神的题解[就是上面那个网址],看到下面这段话 观察题目,发现一串数s(l~r)整除p满足s(l~n-1)%p==s(r+1~n-1)%p 但p值为2或5不满足这个性质需要特判(不过数据中好像没有,于是笔者没写,有兴趣的可以自己去写写......) 然后问题转化为求一段区间中有几对相等的f值. 看到这里,我感觉豁然开朗,完全忽视了离散化的要求,我以为把

【bzoj5452】[Hnoi2016]大数(莫队)

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4542 首先若p=2,5则这题就是道傻逼题,前缀和搞一下没了.如果p为其他质数,那么可以这么处理: 我们先预处理出数组num[i]表示原串第i~n位表示的数模p的余数,那么第l~r位表示的数模p的余数为(num[l]-num[r+1])/10^(n-r),因为10^(n-r)与p互质,所以若num[l]=num[r+1],则第l~r位表示的数是p的倍数.于是莫队一下就好了. 代码: #

【BZOJ】4542: [Hnoi2016]大数

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4542 给定一个由数字构成的字符串${S_{1,2,3,...,n}}$,一个正素数$P$,每次询问给定一对$l$,$r$求: $${\sum_{l=1}^{n}\sum_{r=i}^{n}\left [ \sum _{i=l}^{r}S[i]*10^{r-i} \,\,\,\,MOD\,\,\,\,P=0 \right ]}$$ 即以位置$x$开头的后缀的数字$%P$之后的值为$val[

4542: [Hnoi2016]大数|莫队

HN一天考两个莫队是什么鬼..或者说莫队不是正确的姿势..? 考虑已经知道了l..r的答案新添入r+1如何更新当前答案 需要先预处理出后缀modp的值bi,假设子序列l..r模p的值为x 那么x?10r?l+b[r]=b[l] 然后就可以直接莫队统计了 模数为2或5的时候要特判一下 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cs