zoukankan      html  css  js  c++  java
  • 联赛%你测试10T2:漫无止境的八月

    题意:

    思路:
    有几个特殊的性质:

    • 在不考虑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)查询总没问题吧
      1. 评测机没开c++11,根本用不了。
      2. unordered_map实测也会T。
    • 所以这道题想通过这种方法a掉,就只剩两种方法了:
      1. 运用神仙快读fread()+强行预编译c++11
      2. 手打哈希表。

    就没别的办法了吗???

    当然有。
    我们考虑差分(区间问题的一种可行性方法),先建出来差分数组。
    每次修改是对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;
    }
    
  • 相关阅读:
    关于hibernate中多对多关系
    选择排序
    Offer是否具有法律效力?
    textarea文本域宽度和高度(width、height)自己主动适应变化处理
    序列相关的趣题 之三
    windows的定时任务设置
    Maven pom.xml 配置详解
    PS 图像特效-非线性滤波器
    PS 滤镜算法原理——拼贴
    PS 滤镜算法原理——曝光过度
  • 原文地址:https://www.cnblogs.com/liu-yi-tong/p/13776763.html
Copyright © 2011-2022 走看看