洛谷题解-[ABC288D] Range Add Query (差分+分类)

题目:

[ABC288D] Range Add Query - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

大意:

一些数,选一个区间A(L~R),并再选一个区间B(长度k),这个区间B的每个数加减(加负数=减一个数)一个数,最终使得区间A全部数为0

举个例(样例)

0.    3 -1 1 -2 2 0

1.    0 -4 -2 -2 2 0  (-3)

2.    0 0 2 2 2 0   (+4)

3.    0 0 0 0 0 0   (-3)

所以最终为“Yes”(注意大小写问题

 

思路:

刚开始就可以想到是差分了,因为是区间加减数,但是具体的不知道怎么做,也是想了比较久的时间的,很有意思

在解这题前得知道差分是什么(就是前缀和的逆)

然后要了解一个性质,例如有一个数列    (位:第几个数)

位1 2 3 4 5 6

值3 2 1 5 1 2

我们得让2~4的数加2,可以这样写

位1   2   3  4   5   6

值0 +2   0  0  -2   0  

这样的话这个区间也算是每项加2了,因为第2位加了2,后面的会跟着加2,但是在第4位加完2,第5位得减回来,不然会超出范围

前置知识了解完就可以看思路了

 

 

最终,A数组加减一堆数,肯定全为0了(输出Yes的情况),那么B数组也会变成{-a1, 0, 0, 0.... 0}。由于我们要选长度为k的区间B,考虑加减一个数。所以每个数(A数组)可以对应一个余数(%k),来方便我们找规律,如下

A数组 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12
余数  1  2  3  4   1 2  3  4  1   2  3    4
B数组 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12
B最终 -a1 0 0  0  0  0  0  0  0   0  0    0



这里我们定,s[i][j]表示前i个数余数为j的差分数组的和,会发现有3种情况,区间内同余数和一定为0,肯定相同,但是还有左右端点要特判,所以分情况

情况1,当下标为i=(R+1)%k     L+b[L]==0                          在区间内,自然的
情况2,当下标为i==L mod k    S[R][余]-s[L-1][余]==-a[L-1]        像b[1]最终为-a1一样,不过这里的位置不固定,换成a[L-1]
情况3,当下标i区间L,R内      s[R][余]-s[L-1][余]==0              在区间外没余数这个值了




具体可以看代码,里面的注释也很详细了
#include <bits/stdc++.h>
using namespace std;

const int N=2e5+5, M=11;
int n, k, a[N], b[N], s[N][M], m, L, R;
//s[i][j]:前i个数余数为j的差分数组的和
//b:差分数组 
int yu(int x) //求余 例如4%3=1, 4%4=4 
{
	return (x-1)%k+1;
}
int main()
{
	scanf("%d%d", &n, &k);
	for (int i=1; i<=n; i++) 
	{
		scanf("%d", &a[i]);
		b[i]=a[i]-a[i-1];
	}
	//b最终:  -a1 0 0 0 ... 0 
	for (int i=1; i<=n; i++)
	{
		for (int j=1; j<=k; j++) s[i][j]=s[i-1][j]; //余数相等,必然有 i=i-1
		s[i][yu(i)]+=b[i]; //余数不同,加上此差分数组的数 
	}
	scanf("%d", &m);
	while (m--)
	{
		int flag=0;
		scanf("%d%d", &L, &R);
		for (int i=L; i<=L+k-1; i++) //遍历区间,不用全部跑,因为余数最多为L+k-1 
		{
			int j=yu(i);
			if (j==yu(R+1)) continue;//情况1不考虑,因为b数组都为0,在区间内无影响
			
			if (j==yu(L)) //情况2 
			{
				if (s[R][j]-s[L-1][j]!=-a[L-1]) 
				{
					flag=1;
					break;
				}
			} 
			else //情况3 
			{
				if (s[R][j]-s[L-1][j]!=0) 
				{
					flag=1;
					break;
				}
			}
		
		
		}	
		if (flag==1) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}
/*
A数组 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12
余数  1  2  3  4   1 2  3  4  1   2  3    4
B数组 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12
B最终 -a1 0 0  0  0  0  0  0  0   0  0    0
区间     2                       10              (选2~10)
         2           2            2             情况2,当下标为i==L mod k    S[R][余]-s[L-1][余]==-a[L-1] 
            3          3            3           情况1,当下标为i=(R+1)%k     L+b[L]==0
               4           4              4     情况1,同上 
                  1           1					情况3,当下标i区间L,R内      s[R][余]-s[L-1][余]==0 
*/

  

 

第一次写题解,有不足请指出,谢谢!

posted @ 2024-01-22 19:42  cn是大帅哥886  阅读(65)  评论(0)    收藏  举报