【二维差分】2018-2019ICPC焦作J - Carpets Removal
关键 易错
【二维前缀和&差分】
前缀和:
$$sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + {\color{Red} {a[i][j]}}$$
差分操作:
$a[x1][y1]$++$;$
$a[x1][y2+1]$--$;$
$a[x2+1][y1]$--$;$
$a[x2+1][y2+1]$++$;$
p.s. 可用同一个数组
【题目描述】
【题解】
利用二维差分记录每个格子被覆盖的次数 $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]$
$x^{2}+y^{2}=b[i][j]$
可得
$x=\frac{a-\sqrt{2b-a^{2}}}{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); //先处理重合的情况,再排序,否则num数组就乱了 ans=max(ans,num[n]+num[n-1]); printf("%lld\n",tot-ans); } return 0; }

浙公网安备 33010602011771号