題目鏈接
真細節題… 選了一個很複雜的作法。
ios
枚舉第一個做者 A A A選的框,枚舉選手 i i i。你會發現另外一個做者 B B B選的框對於選手 i i i來講,會有一些右端點連續的區間比 A A A更優。那這樣就能夠知道做者 B B B選哪些框更優而且也能用二次差分統計出優多少。
搞完全部選手後,找出做者 B B B選哪一個框最優便可。
c++
二次差分的模板:spa
void add(int l,int r,int op,int d){ //區間[l,r] 加上op爲首項,d爲公差的等差數列 tw[l]+=d; tw[r+1]-=d; cat[l]+=op-d; cat[r+1]-=op-d; cat[r+1]-=d*(r+1-l); }
分類討論的細節還但願讀者能夠本身多想一想,理清楚。。。。。(由於我也是由於細節問題 debug了好久…)debug
細節見代碼:code
//#pragma GCC optimize(2) //#pragma GCC optimize(3) #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 2e3 + 10; #define fi first #define se second #define pb push_back #define wzh(x) cerr<<#x<<'='<<x<<endl; int n,m,k; struct uzi{ int l,r; }p[N]; int a[N][N],L[N][N],R[N][N]; int cat[N],tw[N]; int F[N],G[N]; void add(int l,int r,int op,int d){ tw[l]+=d; tw[r+1]-=d; cat[l]+=op-d; cat[r+1]-=op-d; cat[r+1]-=d*(r+1-l); } void solve(int x,int y,int z){ //多的 int mx=min(k,p[x].r-p[x].l+1); if(L[x][y+1]<L[x][mx]){ //左邊等差 int l=L[x][mx-1]; add(L[x][y+1],l,1,1); }else if(a[F[x]][x]>y&&a[F[x]][x]!=mx){ add(F[x],L[x][mx]-1,a[F[x]][x]-y,1); } add(L[x][mx],R[x][mx],mx-y,0);//中間一段恆等 if(G[x]>R[x][mx]&&y+1<mx&&R[x][y+1]>R[x][mx]){ //第三段等差 int dx=R[x][mx-1]; int dy=R[x][y+1]; add(dx,dy,mx-y-1,-1); }else if(a[G[x]][x]>y && a[G[x]][x]!=mx){ add(R[x][mx]+1,G[x],mx-y-1,-1); } } void solve_(int x){ int l=F[x],r=G[x]; int mx=min(k,p[x].r-p[x].l+1); int dx=L[x][mx],dy=R[x][mx]; add(dx,dy,mx,0); if(l<dx)add(l,dx-1,a[l][x],1); if(r>dy)add(dy+1,r,mx-1,-1); } int main() { ios::sync_with_stdio(false); cin>>n>>m>>k; for(int i=1;i<=m;i++)cin>>p[i].l>>p[i].r; for(int i=k;i<=n;i++){ int x=i-k+1,y=i; for(int j=1;j<=m;j++){ int l=p[j].l,r=p[j].r; if(r<x||l>y)continue; l=max(l,x); r=min(r,y); a[i][j]=r-l+1; } } for(int i=1;i<=m;i++){ for(int j=k;j<=n;j++){ if(a[j][i]){ if(!F[i])F[i]=j; G[i]=j; if(!L[i][a[j][i]])L[i][a[j][i]]=j; R[i][a[j][i]]=j; } } } int ok=0; for(int i=k;i<=n;i++){ int res=0; for(int j=1;j<=m;j++)res+=a[i][j]; for(int j=1;j<=m;j++){ int now=a[i][j]; if(now==k)continue; if(now==p[j].r-p[j].l+1)continue; if(now)solve(j,now,i); else solve_(j); } int pp=0; for(int j=1;j<=n;j++){ tw[j]+=tw[j-1]; cat[j]+=cat[j-1]+tw[j]; pp=max(pp,cat[j]); } for(int j=0;j<=n+1;j++)cat[j]=tw[j]=0; res+=pp; ok=max(ok,res); } cout<<ok<<'\n'; return 0; }