题目链接
真细节题… 选了一个很复杂的作法。
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; }