思路:以前沒做過差分的題目,這題想不到用差分,感覺很神奇。
思路:構造差分序列b【i】=a【i】-a【i-1】,比如1 3 2 5 1的差分序列就是1 2 -1 3 -4,這樣将區間【l,r】内的所有數減一相當于把b【l】減一, 把b【r+1】加一,基于這個思想我們從左到右掃整個序列,遇到正數就找他右面離他最近的負數,把這個負數盡量變為0,變為0後若正數還有剩餘,就繼續往右找負數直到這個正數用完,當然找到負數以後要判斷一下負數與正數之間的距離是否小于三,小于三肯定不滿足題意了,直接輸出no就好了,這樣掃完整個序列後差分數組的每個數應該都是0,都是0的話輸出yes,否則no
上面的分析已經很透徹了,這裡講一下為什麼隻要保證距離不小于三就行(題目要求可以打出3,4,5張牌),其實也很好了解,我們将打牌轉化成了區間減去1的問題,隻要這個區間大于等于3,那麼不管它是多少,都可以分解成3,4,5這樣的子區間,是以隻要保證不小于三就行。
下面補充點差分的性質:
差分就是将一串數分别于前一個數做差,例如:
一個序列1 2 5 4 7 3,差分後得到1 1 3 -1 3 -4 -3
這裡注意得到的差分序列第一個數和原來的第一個數一樣(相當于第一個數減0)
差分序列最後比原序列多一個數(相當于0減最後一個數)
性質:
1、差分序列求字首和可得原序列
2、将原序列區間[L,R]中的元素全部+1,可以轉化操作為差分序列L處+1,R+1處-1
3、按照性質2得到,每次修改原序列一個區間+1,那麼每次差分序列修改處增加的和減少的相同
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=2e5+7;
const int mod=1e9+7;
ll a[maxn],sum[maxn];
int n;
bool solve()
{
int pos=4;
for(int i=1;i<=n+1;i++)
{
while(sum[i]>0)
{
while(pos<=n+1&&sum[pos]>=0) pos++;
if(pos>n+1||pos-i<3) return false;
if(sum[pos]+sum[i]>=0)
{
sum[i]+=sum[pos] ;
sum[pos]=0;
}
else
{
sum[pos]+=sum[i];
sum[i]=0;
}
}
if(sum[i]!=0) return false;
}
return true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
int Case=0;
while(T--)
{
scanf("%d",&n);
a[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=a[i]-a[i-1];
}
sum[n+1]=0-a[n];
bool ans=solve();
printf("Case #%d: ",++Case);
if(ans)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
return 0;
}