傳送門:http://acm.ecnu.edu.cn/contest/11/problem/F/
麗娃河是華師大著名的風景線。但由於學校財政緊缺,麗娃河邊的路燈年久失修,一到晚上就會出現走在河邊要打着手電的情況,不僅非常不方便,而且影響安全:已經發生了大大小小的事故多起。
方便起見,麗娃河可以看成是從 1 到 n 的一條數軸。爲了美觀,路燈只能安裝在整數點上,每個整數點只能安裝一盞路燈。經專業勘測,有 m 個區間特別容易發生事故,所以至少要安裝一定數量的路燈,
請問至少還要安裝多少路燈。
Input
第一行一個整數 T (1≤T≤300) ,表示測試數據組數。
對於每組數據:
-
第一行三個整數 n,m,k (1≤n≤10 3 ,1≤m≤10 3 ,1≤k≤n) 。
-
第二行 k 個不同的整數用空格隔開,表示這些位置一開始就有路燈。
-
接下來 m 行表示約束條件。第 i 行三個整數 l i ,r i ,t i 表示:第 i 個區間 [l i ,r i ] 至少要安裝 t i 盞路燈 (1≤l i ≤r i ≤n,1≤t i ≤n) 。
Output
對於每組數據,輸出 Case x: y
。其中 x 表示測試數據編號(從 1 開始),y 表示至少要安裝的路燈數目。如果無解,y 爲−1 。
Examples
Input
3 5 1 3 1 3 5 2 3 2 5 2 3 1 3 5 2 3 2 3 5 3 5 2 3 1 3 5 2 3 2 4 5 1
Output
Case 1: 1 Case 2: 2 Case 3: 1
Note
因爲今天不是滿月,所以狼人沒有出現。
題解:
按右端點排序,然後對於不滿足條件的儘量往右壘就好了。貪心的證明:由於左邊的都已經壘滿了,所以壘左邊的肯定是沒意義的。壘中間肯定沒有壘右邊的號,因爲右邊的區間不可能長得斷開,使得壘在左邊收益更大。這樣就可以實現O(n 2 ) 。
本題雖然不作要求,但是可以做到 O(nlog 2 n) ,用線段樹維護,不符合條件可能需要二分。具體細節留給讀者思考。
模仿Q巨AC代碼#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1005;
int usd[MAXN],l[MAXN],r[MAXN],t[MAXN],id[MAXN];
int main()
{
int T;
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
memset(usd,0,sizeof(usd));
for(int i=1;i<=k;i++)
{
int x;
scanf("%d",&x);
usd[x]=1;
}
int gg=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&l[i],&r[i],&t[i]),id[i]=i;
gg|=(t[i]>r[i]-l[i]+1);
for(int j=1;j<=n;j++)
t[i]-=(l[i]<=j && j<=r[i] && usd[j]);
}
if(gg)
{
printf("Case %d: %d\n",ca,-1);
continue;
}
sort(id+1,id+m+1,[](int a,int b){return r[a]<r[b];});
int res=0;
for(int ii=1;ii<=m;ii++)
{
int i=id[ii];
for(int j=r[i],k=t[i];k>0;j--)
{
if(usd[j])continue;
for(int s=1;s<=m;s++)
t[s]-=(l[s]<=j && j<=r[s]);
usd[j]=1,k--,res++;
}
}
printf("Case %d: %d\n",ca,res);
}
return 0;
}