P4754 True Vegetable
阅读原文时间:2021年04月20日阅读:1

小A现在有 NN 道题,编号为 1,2,\cdots,N1,2,⋯,N 。每道题的起始毒瘤程度为 00 或 11 。在每回合,小A可以将编号连续的 KK 道题的毒瘤程度+1。但小B因为本身比较菜,不是很愿意小A出毒瘤题,所以在 w_iwi​ 回合开始时可以向第 x_ixi​ 题传播 v_ivi​ 点的菜气,使得第 x_ixi​ 的毒瘤程度减少 v_ivi​ 点(减后可以为负)。这里我们假定菜是有限的,在释放了 v_ivi​ 点的菜气后,小B需要至少 r_{v_i}rvi​​ 个回合不能释放菜气。现在小A知道了小B释放菜气的计划,他想知道他至少需要多少个回合可以使得每道题的毒瘤程度至少为 11 。

输入格式:

第一行输入四个整数, N,M,K,LN,M,K,L ,分别为题目的数量,小B的操作数量,每次连续增加毒瘤程度题目的数量和释放菜气的最大值。

第二行输入 NN 个整数 a_1,a_2,\cdots,a_Na1​,a2​,⋯,aN​ ,分别为 NN 个题目的毒瘤程度。

第三行输入 LL 个整数 r_1,r_2,\cdots,r_Lr1​,r2​,⋯,rL​ ,分别为释放 11 到 LL 点菜气的冷却回合数。

接下来有 MM 行,每行输入三个整数 w_i,x_i,v_iwi​,xi​,vi​ ,表示小B在第 w_iwi​ 回合开始时向第 x_ixi​ 题释放了 v_ivi​ 点的菜气。保证 \{w_i\}{wi​} 为递增序列。

输出格式:

请输出小A将每道题的毒瘤程度加到至少为 11 最少需要的回合数。

输入样例#1:

6 1 3 2
0 0 0 0 0 0
1 2
2 1 1

输出样例#1:

3

输入样例#2:

6 1 3 2
1 0 0 0 0 0
1 2
2 1 1

输出样例#2:

2

输入样例#3:

6 1 6 2
0 0 0 0 0 0
1 2
2 1 1

输出样例#3:

1

1≤N,M≤5×105

1≤K≤N

1≤L≤100

a[i]∈{0,1}

1=r1​<r2​<⋯<rL​≤2×L

1≤wi​≤N+L

wi​+rvi​​≤wi+1​

1≤xi​≤N

1≤vi​≤L

Solution:

  本题也是贼有意思,考查细心读题。

  题目中明确的说了$w_i+r_{v_i}\leq w_i+1$,于是可以想到,当某个位置的值减少后,完全可以通过冷却的时间来恢复。

  令被减去的时间为时间点,考虑二分被减的时间点,然后将难度先减去要减的值,因为减难度的冷却时间不小于需要加的数量,被减的数量可以用相同数量的时间填补,所以当一个时间点可以达到目标时,下一个时间点必然也能达到目标。

  然后在时间点上计算出需要的时间。二分时间点,在减去生效的操作后,我们可以贪心地从左到右地考虑,当位置$i$小于$1$时,考虑贪心地将$[i,i+k-1]$这个区间加$1$,可以使需要的回合数尽量小。当确定小B有哪些操作生效时,这样就可以求出满足条件的准确最小时间,若这个时间小于下个时间点,那么check()就是有效的。

  时间复杂度$O(n\log n)$

代码:

#include
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
int n,m,k,L,a[N],R[N],tp[N],b[N];
struct node {
int w,x,v;
}t[N];

il int gi(){
int a=;char x=getchar();bool f=;
while((x<''||x>'')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=;
while(x>=''&&x<='')a=(a<<)+(a<<)+x-,x=getchar();
return f?-a:a;
}

il int check(int mid){
For(i,,n) tp[i]=a[i],b[i]=;
For(i,,mid) tp[t[i].x]-=t[i].v;
int tmp=,tot=,dis;
For(i,,n){
if(tp[i]+tmp<){
dis=-tp[i]-tmp;
tot+=dis;
b[i]+=dis;
if(i+k-<=n) b[i+k-]-=dis;
}
tmp+=b[i];
}
return max(t[mid].w,tot);
}

int main(){
n=gi(),m=gi(),k=gi(),L=gi();
For(i,,n) a[i]=gi(); For(i,,L) R[i]=gi();
For(i,,m) t[i].w=gi(),t[i].x=gi(),t[i].v=gi();
t[].w=,t[m+].w=;
int l=,r=m,mid,ans;
while(l<=r){ mid=l+r>>;
if(check(mid)<t[mid+].w) ans=mid,r=mid-;
else l=mid+;
}
cout<<check(ans);
return ;
}