[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)
Posted 鲸头鹳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)相关的知识,希望对你有一定的参考价值。
正经题解在最下面
写的时候看了大神的题解[就是上面那个网址],看到下面这段话
观察题目,发现一串数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 }
以上是关于[BZOJ4542] [JZYZOJ2014][Hnoi2016] 大数(莫队+离散化)的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ 720][JZYZOJ 2016]gty的妹子树 强制在线 树分块/树套树
JZYZOJ1998 [bzoj3223] 文艺平衡树 splay 平衡树