没做出来,上网看人家的题解后终于明白了。
其实做的时候也发觉了,这应该是一道差分题。但是究竟应该如何差分呢?对什么进行差分呢?搞不明白。
在这道题中,我们可以O(n^2)的计算出所有的一个区间的覆盖。
但是,两个区间的话怎么比较他们的最大值呢?
总不能O(m)的一一对照吧!那样的话就O(n^2m)不行!
所以该怎么办呢?
看了大佬的博客,发现大佬维护了这么一个东西sub[i][j]
意为:有两个k区间一个是以i为开头一个是以j为开头
以i为开头的区间因为以j为开头的区间而减去的贡献。
为什么要维护这个东西呢?
因为事实上,在我们计算m中每一个区间对当前k区间的贡献度的时候,我们是可以计算出比此时贡献度小的k区间在哪里,比此时贡献度大的k区间在哪里。
这些区间具有连续性,我们可以用差分维护。
但是困难来了。如果两个区间的贡献度相同呢?
我们当然也算,那么在减去的时候其实就是减去双倍了。
所以,对于整体我们都要维护双倍。
这里的差分极为讲究!!!
#include<iostream> #include<algorithm> using namespace std; int n,m,k; int lft[2100],rgt[2100]; int res[2100],sub[2100][2100]; void Solve(int l){ int r = l+k-1; for (int i=1;i<=m;++i){ int a = min(r,rgt[i])-max(l,lft[i])+1; a=max(a,0);res[l]+=a; if (a == k||a == rgt[i]-lft[i]+1){ sub[l][max(1,lft[i]+a-k)]+=a; sub[l][rgt[i]-a+2]-=a; } else{ sub[l][max(1,lft[i]+a-k)]+=a; sub[l][max(1,lft[i]+a-k+1)]+=a; sub[l][rgt[i]-a+1]-=a; sub[l][rgt[i]-a+2]-=a; } }for (int i=1;i+k-1<=n;++i)sub[l][i]+=sub[l][i-1]; } int main(){ scanf("%d %d %d",&n,&m,&k); for (int i=1;i<=m;++i) scanf("%d %d",&lft[i],&rgt[i]); for (int i=1;i+k-1<=n;++i) Solve(i); int ans = 0; for (int i=1;i+k-1<=n;++i) for (int j=i;j+k-1<=n;++j) ans = max(ans,res[i]+res[j]-(sub[i][j]+sub[j][i])/2); printf("%d\n",ans); }