P11509 [ROIR 2017 Day 1] 挖矿机器人
Assembly_line · · 题解
等了一周还没等到题解/qd。
做法来自官方题解。俄语翻译真的难以理解。
首先二分答案,判断前
将问题转为二分图匹配,左部点为每个机器人,右部点为每个位置(每个格子对应着
直接建出二分图显然会爆炸,考虑使用 hall 定理 进行判定。
根据 hall 定理,要对每一个子集进行判定,这样显然不可接受。考虑子集中存在移动能力为
于是将每个基地的机器人按照移动能力进行排序,枚举每个基地移动能力的最大值
统计矩形面积并可以用容斥做到
时间
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int w,h,s,q;
int ax[5],ay[5];
int n;
int b[103],d[103];
ll a[103];
//b:foundation
//a:number of bots
//d:distance
ll f[5];
int cnt[5],g[5];
struct node{
ll x;int dis;
}p[5][103];
bool cmp(node x,node y){return x.dis<y.dis;}
struct rec{
int ax,ay,bx,by;
}c[5],I;
rec merge(rec x,rec y)
{
if(x.ax==-1||y.ax==-1)return I;
if(x.ax==0)return y;
if(y.ax==0)return x;
rec c;
c.ax=max(x.ax,y.ax);
c.bx=min(x.bx,y.bx);
c.ay=max(x.ay,y.ay);
c.by=min(x.by,y.by);
if(c.ax>c.bx||c.ay>c.by)c.ax=-1;
return c;
}
ll sqm(rec x)
{
if(x.ax<=0)return 0;
return 1ll*(x.bx-x.ax+1)*(x.by-x.ay+1);
}
ll sq;
void calc(int x,int now,rec w)
{
if(x>s)
{
if(now%2==0)sq-=sqm(w);
else sq+=sqm(w);
return;
}
calc(x+1,now,w);
calc(x+1,now+1,merge(w,c[x]));
}
int flag;
ll res;
void dfs(int x)
{
if(x>s)
{
for(int i=1;i<=s;i++)
{
if(g[i]==-1)c[i]=I;
else
{
c[i].ax=max(1,ax[i]-g[i]);
c[i].bx=min(w,ax[i]+g[i]);
c[i].ay=max(1,ay[i]-g[i]);
c[i].by=min(h,ay[i]+g[i]);
}
}
sq=0;calc(1,0,(rec){0,0,0,0});
ll ss=0;
for(int i=1;i<=s;i++)ss+=f[i];
if(sq*q<ss)flag=0,res=max(res,ss-sq*q);
return;
}
f[x]=0;
for(int i=0;i<=cnt[x];i++)
{
g[x]=p[x][i].dis;
dfs(x+1);
f[x]+=p[x][i+1].x;
}
}
bool check(int x)
{
flag=1;res=0;
for(int i=1;i<=s;i++)cnt[i]=0,p[i][0].dis=-1;
for(int i=1;i<=x;i++)
{
++cnt[b[i]];
p[b[i]][cnt[b[i]]]=(node){a[i],d[i]};
}
for(int i=1;i<=s;i++)sort(p[i]+1,p[i]+cnt[i]+1,cmp);
dfs(1);
return flag;
}
int main()
{
scanf("%d %d %d %d",&w,&h,&s,&q);
for(int i=1;i<=s;i++)scanf("%d %d",&ax[i],&ay[i]);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d %lld %d",&b[i],&a[i],&d[i]);
I.ax=-1;int ans=0;
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
check(ans+1);
printf("%d %lld\n",ans,a[ans+1]-res);
return 0;
}