关于(个人认为的)正解分块被卡 T 一个点那些事

P4168 [Violet] 蒲公英

Zack_zhu @ 2021-06-26 13:37:26

[题目链接](https://www.luogu.com.cn/problem/P4168) ```cpp #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 4e4+5; const int MAXQ = 505; int k[MAXQ][MAXQ],s[MAXQ][MAXN],a[MAXN],lsh[MAXN],l[MAXQ],r[MAXQ],t[MAXN],p[MAXN],pos[MAXN],maxx,now,cnt,n,m,x,y,ans,block; template <typename T> inline void read(T &s) { s = 0; bool w = false; char ch = getchar(); while(ch < '0'||ch > '9') { if(ch == '-') w = true; ch = getchar(); } while(ch >= '0'&&ch <= '9') { s = (s<<3)+(s<<1)+(ch^48); ch = getchar(); } s = w == true ? -s:s; return; } inline void in_block() { memset(t,0,sizeof(t)); maxx = 0; for(int i = x;i <= y;i++)//暴力扫 { t[a[i]]++; if(t[maxx] < t[a[i]]) maxx = a[i]; if(t[maxx] == t[a[i]]) maxx = min(maxx,a[i]); } ans = p[maxx]; return; } inline void out_block() { memset(t,0,sizeof(t)); maxx = 0; for(int i = x;i <= r[pos[x]];i++)//暴力查整块左边的 { t[a[i]]++; if(t[maxx] < t[a[i]]) maxx = a[i]; if(t[maxx] == t[a[i]]) maxx = min(maxx,a[i]); } for(int i = l[pos[y]];i <= y;i++)//暴力查整块右边的 { t[a[i]]++; if(t[maxx] < t[a[i]]) maxx = a[i]; if(t[maxx] == t[a[i]]) maxx = min(maxx,a[i]); } if(maxx == k[pos[x] + 1][pos[y] - 1])//如果相等,直接还原并返回(BTW:p为离散化前对应的值) ans = p[maxx]; else { t[maxx] += s[pos[y] - 1][maxx] - s[pos[x]][maxx];//加上块内的边上求得的众数 int ans2 = t[k[pos[x] + 1][pos[y] - 1]] + s[pos[y] - 1][k[pos[x] + 1][pos[y] - 1]] - s[pos[x]][k[pos[x] + 1][pos[y] - 1]];//块内众数的个数 if(t[maxx] > ans2)//选择答案 ans = p[maxx]; else if(t[maxx] == ans2) ans = p[min(maxx,k[pos[x] + 1][pos[y] - 1])]; else ans = p[k[pos[x] + 1][pos[y] - 1]]; } return; } int main() { read(n); read(m); block = sqrt(n); for(int i = 1;i <= n;i++) { read(a[i]); lsh[i] = a[i]; } sort(lsh+1,lsh+1+n);//离散化 cnt = unique(lsh+1,lsh+1+n) - lsh - 1; for(int i = 1;i <= n;i++) now = a[i],a[i] = lower_bound(lsh+1,lsh+1+cnt,a[i]) - lsh,p[a[i]] = now; for(int i = 1;i <= block;i++)//预处理左右端点 { l[i] = (i - 1) * block + 1; r[i] = i * block; } if(r[block] < n) { l[++block] = r[block - 1] + 1; r[block] = n; } for(int i = 1;i <= block;i++) for(int j = l[i];j <= r[i];j++) pos[j] = i;//每一个位置对应的块的编号 for(int i = 1;i <= block;i++) { for(int j = 1;j <= cnt;j++) s[i][j] += s[i-1][j];//sum数组处理 1 ~ i中j的个数 for(int j = l[i];j <= r[i];j++) s[i][a[j]]++; } for(int i = 1;i <= block;i++) { memset(t,0,sizeof(t));//开桶记录出现了几次。。。 for(int j = i;j <= block;j++) { k[i][j] = k[i][j-1];//k为在块 i ~ j中的众数 for(int z = l[j];z <= r[j];z++) { t[a[z]]++; if(t[k[i][j]] < t[a[z]]) k[i][j] = a[z]; if(t[k[i][j]] == t[a[z]]) k[i][j] = min(k[i][j],a[z]);//暴力预处理 } } } ans = 0; for(int i = 1;i <= m;i++) { read(x); read(y); x = (x + ans - 1) % n + 1; y = (y + ans - 1) % n + 1;//还原左右区间 if(x > y) swap(x,y); if(pos[x] - pos[y] <= 1) in_block();//在同一块内暴力处理 else out_block();//不同块分块处理 printf("%d\n",ans); } return 0; } ```

by Zack_zhu @ 2021-06-26 13:40:04

加了注释方便巨佬们一眼秒掉。。。(BTW,第十八个点 T 了)
好像 memset 还比 for 快。。。


by Zack_zhu @ 2021-06-26 13:42:59

我的时间好慢,但我不知道差在哪,望巨佬们解答,感激不尽!


by StranGePants @ 2021-06-26 15:03:43

@我被JC了 你发这里不如学ZH发灌水区


by 听取MLE声一片 @ 2021-06-26 15:49:40

@我被JC了 我这题 n^(5/3)最大的点就跑了230ms


by Zack_zhu @ 2021-06-26 15:54:29

@听取MLE声一片 az,我还有一堆一点几秒的贴地斩,所以差哪了呢,还想请问一下 orz。


by 听取MLE声一片 @ 2021-06-26 15:55:56

@我被JC了 提交记录呢我看看


by Zack_zhu @ 2021-06-26 15:57:56

这里


by Katyusha_qwq @ 2021-06-26 15:58:48

这东西没人会帮你调的吧。。。


by Zack_zhu @ 2021-06-26 15:59:48

@I_CE_IOI az,您看看呗


by 听取MLE声一片 @ 2021-06-26 16:00:45

@我被JC了 说句实话,分块题挂了真没人帮忙调,自己练吧,所有人都是这么过来的

建议是调整一下码风和块长


| 下一页