题意:给你n个高度,再给你1~n每种高度的数量,已知高度连续的3~5个能消去,问你所给的情况能否全部消去;例:n = 4,给出序列1 2 2 1表示高度1的1个,高度2的2个,高度3的2个,高度4的1个。那么我打出1 1 1(高度1 2 3),1 1 1(高度2 3 4)刚好打完。
思路:对于差分数组我们知道,如果我们对区间L,R加1,那么d[L] += 1, d[R + 1] -= 1,我们可以想象这个序列是由0序列不断进行区间+1操作得到。我们打出差分数组,从左到右遍历,如果遇到正数,那么我们就往右找负数把他消掉,如果这个负数和正数距离小于3那么显然无法构成,其他都可以(大于5时我们可以证出这个距离可以用3 4 5表示);如果遇到负数显然没有正数和他匹配,也不行。
代码:
#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = + ;
const int seed = ;
const ll MOD = 1e9 + ;
const int INF = 0x3f3f3f3f;
ll a[maxn], d[maxn];
int main(){
int T, n, Case = ;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
a[] = ;
for(int i = ; i <= n; i++){
scanf("%lld", &a[i]);
d[i] = a[i] - a[i - ];
}
d[n + ] = -a[n];
int flag = ;
int j = ;
for(int i = ; i <= n; i++){
if(d[i] < ) flag = ;
while(j <= n + && d[i] > ){
if(d[j] < ){
if(j - i < ) flag = ;
if(d[j] + d[i] < ){
d[j] += d[i];
d[i] = ;
}
else{
d[i] += d[j];
d[j] = ;
j++;
}
}
else j++;
}
if(d[i] > ) flag = ;
if(flag) break;
}
printf("Case #%d: ", Case++);
if(flag) printf("No\n");
else printf("Yes\n");
}
return ;
}