关键 易错
【二维前缀和&差分】
前缀和:
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]
差分操作:
a[x1][y1]++; a[x1][y2+1]--; a[x2+1][y1]--; a[x2+1][y2+1]++;
p.s. 可用同一个数组
【题目描述】
Problem - J - Codeforces
【题解】
利用二维差分记录每个格子被覆盖的次数 cnt[i][j],覆盖该格子的地毯的编号和 a[i][j] 和编号平方和 b[i][j]
对于 cnt[i][j] == 1 的格子,a[i][j] 即为覆盖该格子的地毯
对于 cnt[i][j] == 2 的格子,假设覆盖该格子的两个地毯编号为 x 和 y,则已知
x + y = a[i][j]
xy = b[i][j]
可得
x = (a - √(2b-a2))/2
y = a - x
由此,可以统计出被且仅被某块地毯覆盖的格子数 num[i];以及被且仅被某两块地毯覆盖的格子数 mp[pair<ll,ll>(x,y)](x <= y)
对于最终选取的两块地毯,有两种情况:相交或不相交
对于相交的情况:只有相交部分存在只被这两个地毯覆盖的格子时,撤走它们俩才会对结果有贡献。因此遍历格子,当遇到 cnt[i][j] == 2 的格子时,统计撤掉覆盖该格子的地毯(编号 x,y)的结果
num[x] + num[y] + mp[pair<ll,ll>(x,y)] (x <= y)
对于不相交的情况,只需要选出 num[i] 中最大的两个相加。注意这里的逻辑,因为 num[i] 统计的是被且仅被某块地毯覆盖的格子数,所以如果最大的两个其实相交了,他们重合且有效的部分也不会被算在内,因而会在相交的情况中被取代掉
最后取max
【代码】
涉及到的使用生疏的 map 操作:
map<pair<ll,ll>,ll> mp; map<pair<ll,ll>,ll>::iterator it; mp[pair<ll,ll>(x,y)]++; for (it=mp.begin();it!=mp.end();it++){ long long x=it->first.first,y=it->first.second; ans=max(ans,num[x]+num[y]+it->second); }
完整代码:
#include <bits/stdc++.h> #define ll long long using namespace std; const int M=1505,N=3e5+5; int T,n,m,cnt[M][M]; long long a[M][M],b[M][M],num[N],ans,tot; int main() { int x1,y1,x2,y2; scanf("%d",&T); while (T--){ scanf("%d%d",&n,&m); memset(cnt,0,sizeof(cnt)); memset(a,0ll,sizeof(a)); memset(b,0ll,sizeof(b)); for (int i=1;i<=n;i++){ scanf("%d%d%d%d",&x1,&x2,&y1,&y2); cnt[x1][y1]++;a[x1][y1]+=(ll)i;b[x1][y1]+=(ll)i*(ll)i; // cnt[x1][y2+1]--;a[x1][y2+1]-=(ll)i;b[x1][y2+1]-=(ll)i*(ll)i; cnt[x2+1][y1]--;a[x2+1][y1]-=(ll)i;b[x2+1][y1]-=(ll)i*(ll)i; cnt[x2+1][y2+1]++;a[x2+1][y2+1]+=(ll)i;b[x2+1][y2+1]+=(ll)i*(ll)i; } memset(num,0ll,sizeof(num)); map<pair<ll,ll>,ll> mp; map<pair<ll,ll>,ll>::iterator it; tot=0ll; for (int i=1;i<=m;i++) for (int j=1;j<=m;j++){ cnt[i][j]=cnt[i-1][j]+cnt[i][j-1]-cnt[i-1][j-1]+cnt[i][j]; // a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+a[i][j]; // b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+b[i][j]; // if (cnt[i][j]) tot++; if (cnt[i][j]==1) num[a[i][j]]++; else if (cnt[i][j]==2){ long long x=(a[i][j]-(ll)sqrt(2*b[i][j]-a[i][j]*a[i][j]))/2; long long y=a[i][j]-x; if (x>y) {ll t=x;x=y;y=t;} mp[pair<ll,ll>(x,y)]++; } } ans=0ll; for (it=mp.begin();it!=mp.end();it++){ long long x=it->first.first,y=it->first.second; ans=max(ans,num[x]+num[y]+it->second); // } sort(num+1,num+1+n); // ans=max(ans,num[n]+num[n-1]); printf("%lld\n",tot-ans); } return 0; }