[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值。

看到这里,我感觉豁然开朗,完全忽视了离散化的要求,我以为把余数值存起来扫一遍就行了离散个p啊..

写着写着完全参透这道题之后发现离散化的是余数啊,你不离散化怎么存数量啊,不存某个余数数量硬扫肯定超时啊....

然后我暴力硬扫果然[dian]超时了.........

然后老老实实写离散化..........

最重要的:2和5要特判

更重要的:离散化的时候要注意判定0的情况...即等于0时特判,不等0时离散化的赋值不应该从0开始,看加注释的那一段即可,不然会像我一样不停错两个点.....

我的程序200+大牛程序100-行..被吊着打.......我觉得我写的还挺清晰的...虽然完全不简洁

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<cstdio>
  5 #include<algorithm>
  6 using namespace std;
  7 int p,m,s=0,sz;
  8 int a[100010]={};
  9 int bel[100010]={};
 10 int ans[100010]={};
 11 long long mo[100010]={};
 12 long long b[100010]={};
 13 long long re[10][100010]={};
 14 int vis[100010]={};
 15 int tot[10]={};
 16 struct nod{
 17     int x,y;
 18     int id;
 19 }e[100010];
 20 void readin(){
 21     char c=getchar();
 22     while(c<‘0‘||c>‘9‘){
 23         c=getchar();
 24     }
 25     while(c>=‘0‘&&c<=‘9‘){
 26         a[++s]=(int)(c-‘0‘);
 27         c=getchar();
 28     }
 29 }
 30 bool mmp(nod aa,nod bb){
 31     if(bel[aa.x]==bel[bb.x]){
 32         if(aa.y==bb.y){
 33             return aa.x<bb.x;
 34         }
 35         return aa.y<bb.y;
 36     }
 37     return bel[aa.x]<bel[bb.x];
 38 }
 39 void work(){
 40     int l=1,r=0;
 41     int an=0;
 42     for(int i=1;i<=m;i++){
 43         while(l>e[i].x){
 44             l--;
 45             an+=vis[mo[l]];
 46             if(mo[r+1]==mo[l]){
 47                 an+=1;
 48             }
 49             vis[mo[l]]++;
 50         }
 51         while(r<e[i].y){
 52             r++;
 53             vis[mo[r]]++;
 54             an+=vis[mo[r+1]];
 55         }
 56         while(l<e[i].x){
 57             vis[mo[l]]--;
 58             an-=vis[mo[l]];
 59             if(mo[r+1]==mo[l]){
 60                 an-=1;
 61             }
 62             l++;
 63         }
 64         while(r>e[i].y){
 65             an-=vis[mo[r+1]];
 66             vis[mo[r]]--;
 67             r--;
 68         }
 69         ans[e[i].id]=an;
 70     }
 71     for(int i=1;i<=m;i++){
 72         printf("%d\n",ans[i]);
 73     }
 74 }
 75 void work5(){
 76     int l=1,r=0;
 77     int an=0;
 78     for(int i=1;i<=m;i++){
 79         while(l>e[i].x){
 80             l--;
 81             vis[a[l]%p]++;
 82             an+=vis[0];
 83         }
 84         while(r<e[i].y){
 85             r++;
 86             vis[a[r]%p]++;
 87             if(a[r]%p==0){
 88                 an+=r-l+1;
 89             }
 90         }
 91         while(l<e[i].x){
 92             an-=vis[0];
 93             vis[a[l%p]]--;
 94             l++;
 95         }
 96         while(r>e[i].y){
 97             if(a[r]%p==0){
 98                 an-=r-l+1;
 99             }
100             vis[a[r]%p]--;
101             r--;
102         }
103         ans[e[i].id]=an;
104     }
105     for(int i=1;i<=m;i++){
106         printf("%d\n",ans[i]);
107     }
108 }
109 int main(){
110     //freopen("wtf.in","r",stdin);
111     scanf("%d",&p);
112     readin();
113     sz=(int)sqrt((double)s);
114     scanf("%d",&m);
115     for(int i=1;i<=m;i++){
116         scanf("%d%d",&e[i].x,&e[i].y);
117         if(e[i].x>=s){
118             e[i].x=s;
119         }
120         if(e[i].y>s){
121             e[i].y=s;
122         }
123         e[i].id=i;
124     }
125     for(int i=1;i<=s;i++){
126         bel[i]=(i-1)/sz+1;
127     }
128     sort(e+1,e+1+m,mmp);
129     if(p==2||p==5){
130         work5();
131         return 0;
132     }
133     for(int i=0;i<=9;i++){
134         re[i][1]=i%p;
135         tot[i]=1;
136     }
137     for(int i=s,w=1;i>=1;i--){
138         int x=a[i];
139         while(tot[x]<w){
140             tot[x]++;
141             re[x][tot[x]]=re[x][tot[x]-1]*10%p;
142         }
143         mo[i]=(re[x][w]+mo[i+1])%p;
144         b[i]=mo[i];
145         w++;
146     }
147     sort(b+1,b+1+s);
148     int size=unique(b+1,b+1+s)-b-1;
149     for(int i=1;i<=s;i++){//离散化部分....注意一定要特判..
150         if(mo[i]==0){
151             mo[i]==0;
152         }
153         else{
154             mo[i]=lower_bound(b+1,b+1+s,mo[i])-b;//这里-1且输入字符串中没有0时,1会被离散化为0
155         }
156     }
157     work();
158     return 0;
159 }

时间: 2024-11-07 07:26:24

[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)的相关文章

【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] 大数 (莫队)

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行,每行两个整数

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

BZOJ 3289 Mato的文件管理(莫队+离散化求逆序数)

3289: Mato的文件管理 Time Limit: 40 Sec  Memory Limit: 128 MB Submit: 2171  Solved: 891 [Submit][Status][Discuss] Description Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号.为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问.Mato每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料.M

Chika and Friendly Pairs(莫队+离散化+树状数组)

Chika and Friendly Pairs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1164    Accepted Submission(s): 421 Problem Description Chika gives you an integer sequence a1,a2,…,an and m tasks. For

4540: [Hnoi2016]序列|莫队+ST表

考虑现在已经知道了[l,r]的答案新添入一个r+1如何更新答案 也就是右端点在r+1处左端点在l..r+1之间的所有的子序列的答案 可以找出l..r中最小的数的位置p,然后p以及p左侧作为左端点的答案就可以直接计算了 考虑左端点在p+1....r+1时对答案的贡献,可以与处理一个前缀和Si表示以i为右端点的所有子序列的答案之和 那么左端点在p+1....r+1时对答案的贡献就是Sr+1?Sp 其他端点移动的做法也同理 为什么我的莫队跑了17s,而网上的其他莫队只需要5s,人傻自带三倍常数QWQ

【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: [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.第二行

【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的倍数.于是莫队一下就好了. 代码: #