藦兲轮约顁

P4168 [Violet] 蒲公英(题解)

藦兲轮の约顁·2024-04-19 15:13·40 次阅读

P4168 [Violet] 蒲公英(题解)

题目#

题目描述#

输入格式#

输出格式#

数据范围#

![]

样例#

Copy
输入: 6 3 1 2 3 2 1 2 1 5 3 6 1 5 输出: 1 2 1

思路#

暴力#

本题求区间内的最小众数,容易想到去用数组sum[i]表示第i种花的个数,在去便利比较,但是复杂度nm一定会T,这时候就要对暴力进行优化。

分块优化1#

如果我们将所给数列进行分块,记录sum[i][j]每一块中的每一种花的数量,在进行比较,这样在询问的时候就可以少便利中间整块的花,而只便利两边的残缺块即可,但这样仍然会T。
这时候就可以更改sum[i][j]的含义为前i个块中j这一种花的个数。从而减小整块的花的询问复杂度。

代码时间#

这个代码是可以过掉 洛谷,acwing(我只在这两个网站(除了hzoi)上交了)的。

点击查看代码
Copy
#include<bits/stdc++.h> using namespace std; const int maxx=4e4+10; const int maxn=210; int cnt,n,m,ans,res; int belong[maxx],mark[maxx],vis[maxx]; int st[maxn],ed[maxn]; int sum[maxn][maxx]; struct floures { int sp,b,id; }a[maxx]; int read() { int ans=0;bool f=0;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();} return f?~ans+1:ans; } void manba_out(int x) { if(x<0){manba_out('-');x=-x;} if(x>9)manba_out(x/10); putchar(x%10+'0'); } bool cmp(floures x,floures y) { return x.sp<y.sp; } bool cmpp(floures x,floures y) { return x.id<y.id; } inline void lsh() { sort(a+1,a+1+n,cmp); a[1].b=++res; vis[a[1].b]=a[1].sp; for(register int i=2;i<=n;i++) { if(a[i].sp==a[i-1].sp)a[i].b=a[i-1].b; else a[i].b=++res; vis[res]=a[i].sp; } sort(a+1,a+1+n,cmpp); } inline void prepare() { cnt=(int)sqrt(n); for(register int i=1;i<=cnt;i++) { st[i]=(i-1)*cnt+1; ed[i]=i*cnt; } if(ed[cnt]<n) { cnt++; st[cnt]=ed[cnt-1]+1; ed[cnt]=n; } for(register int i=1;i<=cnt;i++) { for(register int j=st[i];j<=ed[i];j++) { belong[j]=i; sum[i][a[j].b]++; } for(register int j=1;j<=res;j++) { sum[i][j]+=sum[i-1][j]; } } } inline int query(int l,int r) { int ans=0,cut=0; memset(mark,0,sizeof mark); if(belong[l]==belong[r]) { for(register int i=l;i<=r;i++) { mark[a[i].b]++; } cut=mark[1]; ans=vis[1]; for(register int i=2;i<=res;i++) { if(mark[i]>cut) { cut=mark[i]; ans=vis[i]; } } return ans; } for(register int i=l;i<=ed[belong[l]];i++) { mark[a[i].b]++; } for(register int i=st[belong[r]];i<=r;i++) { mark[a[i].b]++; } if(belong[r]-1>belong[l]) { for(register int i=1;i<=res;i++) { mark[i]+=(sum[belong[r]-1][i]-sum[belong[l]][i]); if(mark[i]>cut) { cut=mark[i]; ans=vis[i]; } } } else { for(register int i=1;i<=res;i++) { if(mark[i]>cut) { cut=mark[i]; ans=vis[i]; } } } return ans; } int main() { n=read();m=read(); for(register int i=1;i<=n;i++) { a[i].sp=read(); a[i].id=i; } lsh(); prepare(); for(register int i=1;i<=m;i++) { int x,y; x=read();y=read(); int l=(x+ans-1)%n+1; int r=(y+ans-1)%n+1; if(l>r)swap(l,r); ans=query(l,r); manba_out(ans); putchar('\n'); } return 0; }

分块优化2#

上个优化需要去便利花的种类,在极限状态下种类为n,复杂度又成了nm,所以我们可以在记录一个mode[i][j]表示第i个块和第j个块的最小众数,这样就不需要便利颜色了。

点击查看代码
Copy
#include<bits/stdc++.h> using namespace std; const int maxx=4e4+10; const int maxn=210; int cnt,n,m,man,res; int belong[maxx],mark[maxx],vis[maxx]; int st[maxn],ed[maxn]; int sum[maxn][maxx],mode[maxn][maxn]; struct floures { int sp,b,id; }a[maxx]; int manba_in() { int ans=0;bool f=0;char ch=getchar(); while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();} while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();} return f?~ans+1:ans; } void manba_out(int x) { if(x<0){manba_out('-');x=-x;} if(x>9)manba_out(x/10); putchar(x%10+'0'); } bool cmp(floures x,floures y) { return x.sp<y.sp; } bool cmpp(floures x,floures y) { return x.id<y.id; } inline void memset_mark_0(int l,int r) { for(register int i=l;i<=ed[belong[l]];i++) { mark[a[i].b]=0; } for(register int i=st[belong[r]];i<=r;i++) { mark[a[i].b]=0; } } inline void lsh() { sort(a+1,a+1+n,cmp); a[1].b=++res; vis[a[1].b]=a[1].sp; for(register int i=2;i<=n;i++) { if(a[i].sp==a[i-1].sp)a[i].b=a[i-1].b; else a[i].b=++res; vis[res]=a[i].sp; } sort(a+1,a+1+n,cmpp); } inline void prepare() { cnt=(int)sqrt(n); for(register int i=1;i<=cnt;i++) { st[i]=(i-1)*cnt+1; ed[i]=i*cnt; } if(ed[cnt]<n) { cnt++; st[cnt]=ed[cnt-1]+1; ed[cnt]=n; } for(register int i=1;i<=cnt;i++) { for(register int j=st[i];j<=ed[i];j++) { belong[j]=i; sum[i][a[j].b]++; } for(register int j=1;j<=res;j++) { sum[i][j]+=sum[i-1][j]; } } for(register int i=1;i<=cnt;i++) { int op,num,opn; for(register int j=i;j<=cnt;j++) { op=mode[i][j-1]; for(register int k=st[j];k<=ed[j];k++) { opn=sum[j][op]-sum[i-1][op]; num=sum[j][a[k].b]-sum[i-1][a[k].b]; if((num>opn)||(num==opn&&vis[op]>vis[a[k].b])) { op=a[k].b; } } mode[i][j]=op; } } } inline int query(int l,int r) { int ans=0,cut=0,val=0; if(belong[l]==belong[r]) { for(register int i=l;i<=r;i++) { mark[a[i].b]++; if((mark[a[i].b]>cut)||(mark[a[i].b]==cut&&ans>a[i].b)) { cut=mark[a[i].b]; ans=a[i].b; } } memset_mark_0(l,r); return vis[ans]; } for(register int i=l;i<=ed[belong[l]];i++) { mark[a[i].b]++; } for(register int i=st[belong[r]];i<=r;i++) { mark[a[i].b]++; } ans=mode[belong[l]+1][belong[r]-1]; for(register int i=l;i<=ed[belong[l]];i++) { cut=sum[belong[r]-1][ans]-sum[belong[l]][ans]+mark[ans]; val=sum[belong[r]-1][a[i].b]-sum[belong[l]][a[i].b]; if((mark[a[i].b]+val>cut)||(mark[a[i].b]+val==cut&&vis[a[i].b]<vis[ans])) { ans=a[i].b; } } for(register int i=st[belong[r]];i<=r;i++) { cut=sum[belong[r]-1][ans]-sum[belong[l]][ans]+mark[ans]; val=sum[belong[r]-1][a[i].b]-sum[belong[l]][a[i].b]; if((mark[a[i].b]+val>cut)||(mark[a[i].b]+val==cut&&vis[a[i].b]<vis[ans])) { ans=a[i].b; } } memset_mark_0(l,r); return vis[ans]; } int main() { n=manba_in();m=manba_in(); for(register int i=1;i<=n;i++) { a[i].sp=manba_in(); a[i].id=i; } lsh(); prepare(); for(register int i=1;i<=m;i++) { int x,y; x=manba_in();y=manba_in(); int l=(x+man-1)%n+1; int r=(y+man-1)%n+1; if(l>r)swap(l,r); man=query(l,r); manba_out(man); putchar('\n'); } return 0; }
posted @   藦兲轮の约顁  阅读(40)  评论(5)    收藏  举报
相关博文:
阅读排行:
· 记一次SSD性能瓶颈排查之路——寿命与性能之间的取舍
· 2025 年实用、全面的 VS Code 插件推荐!
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(五):使用.NET为树莓派
· dify打造数据可视化图表
· C# 模式匹配全解:原理、用法与易错点
点击右上角即可分享
微信分享提示
目录