题目概述
有一个
len×len
的网格图,中央
k×k
的子网格存有毒药(可怕),小偷可以水平或竖直射箭偷走毒药(真奇葩)。有
n
条水平或竖直的蛇,不管箭是射进来还是射出去都可以挡住箭(这题目越来越奇怪了),问最少多少只蛇能够防止小偷偷走毒药。
解题报告
因为蛇是水平或竖直的,不可能同时挡住水平面上的箭和竖直面上的箭。所以我们可以把二维平面上的问题变成一维线段覆盖问题。然后感觉就变成普及组傻逼题了……
线段覆盖问题我们有贪心的策略:假设目前最远覆盖到
示例程序
#include<cstdio>
#include<algorithm>
using namespace std;
#define Fir first
#define Sec second
const int maxn=100000;
int te,len,K,n,L,R,Row,Col;
pair<int,int> row[maxn+5],col[maxn+5];
inline bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return ch;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
int Solve(int n,pair<int,int> *a)
{
int i=1,now=L,ans=0;
while (i<=n&&now<=R)
{
if (a[i].Fir>now) return -1;int MAX=0;
while (i<=n&&a[i].Fir<=now) MAX=max(MAX,a[i].Sec),i++;
now=MAX+1;ans++;
}
if (now<=R) return -1;
return ans;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (readi(te);te;te--)
{
readi(len);readi(K);readi(n);L=(len-K)/2+1;R=L+K-1;Row=0;Col=0;
for (int i=1,x_s,y_s,x_t,y_t;i<=n;i++)
{
readi(x_s);readi(y_s);readi(x_t);readi(y_t);
if (x_s>x_t||x_s==x_t&&y_s>y_t) swap(x_s,x_t),swap(y_s,y_t);
if (L<=x_t&&x_s<=R) row[++Row]=make_pair(x_s,x_t);
if (L<=y_t&&y_s<=R) col[++Col]=make_pair(y_s,y_t);
}
if (!Row||!Col) {printf("-1\n");continue;}
sort(row+1,row+1+Row);sort(col+1,col+1+Col);
int ansR=Solve(Row,row),ansC=Solve(Col,col);
if (~ansR&&~ansC) printf("%d\n",ansR+ansC); else printf("-1\n");
}
return 0;
}