題意:
思路:
有幾個特殊的性質:
- 在不考慮q里面的單點修改,我們先只判斷一個序列是否Yes。
- 我們注意到每次操作都是對一個長度為k的區間進行區間加減1的操作,所以我們如果將序列里面的數按%k分組,把同一組的數都加在一起,那每次操作就一定是給每一個組都加上或減去一個1,因為連續的k長度中,一定是每一組都有且只有一個數受到處理。
- 因為我們自己的操作是區間加減,那么操作是可逆的,如果這個序列能變成全0的序列,那么他也一定可以由全0的序列轉移過來,全0的序列每一組的和都是0,進行幾次操作后,只會給每一組都加上或減去一些1。所以如果一個序列可以由全0序列轉移來,那么它每一組數的和都一定相等。
- 加上單點修改后,會有什么改變呢?
- 很顯然,會改變某一組的和。
- 如果改變后所有組的和都相等,那么輸出Yes,否則輸出No
- 這樣\(O(n)\)查詢顯然不行,那我們稍微優化下。
- 我們開個桶,記錄某一個值出現了幾次,如果一個組的和是x,那么vis[x]++;如果一個值的vis是k,那么就說明所有組的和都一樣,那么就輸出yes啦。
- 在修改的時候,我們把修改前的這組和的vis值--,修改后的這組和vis值++,然后判斷就好啦。
然后就完了嗎???
當然不,區間和的值太大了,數組開不下。
有人會說:用map呀,map開的下。
map常數巨大,直接T飛(70分)。
- 有人會說:用unordered_map呀,O(1)查詢總沒問題吧
- 評測機沒開c++11,根本用不了。
- unordered_map實測也會T。
- 所以這道題想通過這種方法a掉,就只剩兩種方法了:
- 運用神仙快讀fread()+強行預編譯c++11
- 手打哈希表。
就沒別的辦法了嗎???
當然有。
我們考慮差分(區間問題的一種可行性方法),先建出來差分數組。
每次修改是對i加一個值對i+k減去同一個值。
那我們再按%k分組求和,發現無論如何更改,每一組的和都是不變的(因為i和i+k在一組里)。
因為全0序列的差分數組每一組的和都是0,那么只要一個序列每一組和都是0,那就Yes。
一個特判:
我們發現原序列的最后一段區間n-k+1~n,通過差分數組的處理,是給n-k+1的位置上加一個值,再給n+1的位置上減一個值。但是n+1位置上是沒有數的。所以我們得出一個驚人的事實:
n+1所在那個組的和是隨便選的!!!
因為你修改這個組的數的時候,因為n+1這個位置上沒有數,那就是隨便選,那當然無論怎樣這組的和都可以看作0。
我自己的口胡證明:
n+1這一組之所以特殊,是因為這一組的最后一項chafen[n-k+1]的修改比較特殊,我們在處理原序列的最后一段n-k+1~n這一段時候,對應到差分數組上是只給chafen[n-k+1]進行加減的,而其他的區間都是前面加上一個,后面再減回去一個。所以我們可以認為,無論原序列如何,可以做到只更改chafen[n-k+1]而不對其他的差分數組的值產生影響,那么無論這一組差分數組的和是多少,我們可以通過人為調控chafen[n-k+1]的值使得這一組的和最后變為0。因此,這一組的和是任取的。
所以詢問一個區間是否Yes,只要看它差分后的所有組(除了n+1那組)是不是和都是0即可。
我的做法deepinc&skyh學長的處理方法是:
- 先掃一遍給的序列,算出差分數組。記錄每組和,如果有某組和不是0,那么cnt++。如果掃完后cnt==0就Yes否則就No。(需特判n+1%k這組)
- 每次單點修改,就是對pos所在的組加上一個數,對pos+1所在的組減去一個數(差分數組的性質)
- 如果有一個組的和由非0變成了0那么cnt--,如果一個組的和由0變成了非0,那么cnt++。每一個修改過后,直接看cnt==0就Yes。(注意:如果pos或pos+1所在的組有在n+1%k那組的,那這一組就不用處理上面的這些了)
附上丑碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+10;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int a[maxn],chafen[maxn],num[maxn];
int n,k,q;
int main(){
freopen("august.in","r",stdin);
freopen("august.out","w",stdout);
n=read();k=read();q=read();
for(register int i=1;i<=n;i++){
a[i]=read();
}
for(register int i=1;i<=n;i++){
chafen[i]=a[i]-a[i-1];
}
for(register int i=1;i<=n;i++){
num[i%k]+=chafen[i];
}
int ignore=(n+1)%k;
int cnt=0;
for(register int i=0;i<k;i++){
if(num[i]){
cnt++;
}
}
if(num[ignore])cnt--;
if(!cnt)puts("Yes");else puts("No");
for(register int i=1;i<=q;i++){
int pos,x;
pos=read();
x=read();
if(pos%k!=ignore){
if(num[pos%k]==0&&num[pos%k]+x!=0)cnt++;
if(num[pos%k]!=0&&num[pos%k]+x==0)cnt--;
num[pos%k]+=x;
}
if((pos+1)%k!=ignore){
if(num[(pos+1)%k]==0&&num[(pos+1)%k]-x!=0)cnt++;
if(num[(pos+1)%k]!=0&&num[(pos+1)%k]-x==0)cnt--;
num[(pos+1)%k]-=x;
}
if(!cnt)puts("Yes");else puts("No");
}
return 0;
}