1. 程式人生 > 實用技巧 >E 倉鼠與珂朵莉(WHU新生賽)

E 倉鼠與珂朵莉(WHU新生賽)

題目連結:https://ac.nowcoder.com/acm/contest/8925/E

題意:定義一個區間的重要程度:max(k*k在區間中的個數)(k為區間中的數),有m個查詢操作,求區間[l,r]間的重要程度。(強制線上)

思路:本題是“暴力美學”的傑出代表,使用分塊可以O(n√n)內完成。首先由於區間中的數在[0,1e9]的範圍內,所以先用離散化。要使用分塊,那就要求出整大塊的答案,左右兩邊不成塊的數在O(√n)內處理即可。所以我們需求出第i塊到第j塊的重要程度f[i][j],暴力列舉左起的i,然後向右處理出f[i][j]即可,複雜度為O(n√n)。至於如何處理零散數,可以維護h[i][j]表示第i塊數j的個數,列舉零散數並加上整塊中該數的個數從而來維護區間重要程度。但是這麼做的話,每次把整塊的數的的個數加起來時需要O(√n)的複雜度,時間顯然爆表。因此,用字首和維護h[i][j]即可。

總步驟:離散化---->分塊---->預處理f[i][j]和字首和sum[i][j]---->進行計算操作(整塊、零散)

程式碼:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define LL long long
LL n,m,a[100100],b[100100],cnt;
LL l[320],r[320],blo,num,bel[100100];
LL vis[100100],sum[320][100100],f[320][320];
void lisan()
{
    sort(b
+1,b+n+1); cnt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b; return; } void fk() { blo=sqrt(n); num=n/blo; if (n%blo) num++; for(int i=1;i<=num;i++) {l[i]=(i-1)*blo+1; r[i]=i*blo;} r[num]=n; for(int i=1;i<=n;i++) bel[i]=(i-1
)/blo+1; return; } void init() { LL now; for(int i=1;i<=num;i++) { now=0; for(int j=i;j<=num;j++) { for(int k=l[j];k<=r[j];k++) { vis[a[k]]++; now=max(now,vis[a[k]]*b[a[k]]); } f[i][j]=now; } for(int j=l[i];j<=n;j++) vis[a[j]]--; for(int j=l[i];j<=r[i];j++) sum[i][a[j]]++; } for(int i=1;i<=num;i++) for(int j=1;j<=cnt;j++) sum[i][j]+=sum[i-1][j]; return; } LL calc(LL ll,LL rr) { LL nl,nr,ret; if (l[bel[ll]]==ll) nl=bel[ll]; else nl=bel[ll]+1; if (r[bel[rr]]==rr) nr=bel[rr]; else nr=bel[rr]-1; ret=0; if (nl!=bel[ll]) { for(int i=ll;i<=r[bel[ll]];i++) { vis[a[i]]++; ret=max(ret,(vis[a[i]]+sum[nr][a[i]]-sum[nl-1][a[i]])*b[a[i]]); } } if (nr!=bel[rr]) { for(int i=l[bel[rr]];i<=rr;i++) { vis[a[i]]++; ret=max(ret,(vis[a[i]]+sum[nr][a[i]]-sum[nl-1][a[i]])*b[a[i]]); } } if (nl<=nr) ret=max(ret,f[nl][nr]); if (nl!=bel[ll]) for(int i=ll;i<=r[bel[ll]];i++) vis[a[i]]--; if (nr!=bel[rr]) for(int i=l[bel[rr]];i<=rr;i++) vis[a[i]]--; return ret; } int main() { LL ans=0,ll,rr; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) {scanf("%lld",&a[i]); b[i]=a[i];} lisan(); fk(); init(); for(int i=1;i<=m;i++) { scanf("%lld%lld",&ll,&rr); ll=(ll^ans)%n+1; rr=(rr^ans)%n+1; if (ll>rr) ll^=rr^=ll^=rr; ans=calc(ll,rr); printf("%lld\n",ans); } return 0; }