abc 288 D (差分)

题目
题意: 给定长度为n的数组a、k。有q组询问,每次询问一个区间是否为good:执行任意次operation,使得区间内所有数变成0.每次operation允许选择一个长度为k的区间,令该区间中的每个数都+c(c为任意常数)。n<=2e5,k<=10
思路: 思考一下题目要求和operation等价于什么。
题目要求全变成0,也就是说要把b[l+1] 到 b[r] 都变成0,b[l] 变成 - a[l-1].
operation相当于对差分数组b[i] + c,b[i+k] - c.
i和i+k模k是相同的。发现模k相等的数的差分数组的和是不变的,一加一减
1.对于模k相同的位置的差分数组的和要求是0才可以,因为每次操作和不变的。
2. 但是注意要特判,对于与l%k相等的位置,差分数组的和应该是-a[l-1].
3. 对于与(r+1)%k相等的位置,无所谓差分数组的和是多少。为什么呢?因为这些位置的最后一个位置操作影响的是b[r+1],它不在[l,r]区间内,所以这些位置就可以任意变,一定能变成符合题意的。
代码:

#include
using namespace std;
const int N = 2e5+10;
int n,m,k,T;
int a[N];
int b[N];
int s[N][11]; //余j的前缀和 
void solve()
{
	cin>>n>>k;
	for(int i=1;i<=n;++i) cin>>a[i],b[i] = a[i] - a[i-1];
	for(int i=1;i<=n;++i)
	{
		for(int j=0;j<k;++j)
		{
			s[i][j] = s[i-1][j];
		}
		s[i][i%k] += b[i];
	}
	cin>>m;
	while(m--)
	{
		int l,r; cin>>l>>r;
		bool flag = 1;
		for(int j=0;j<k;++j)
		{
			if((r+1)%k==j) continue;
			int wh = s[r][j] - s[l-1][j];
			if(j==l%k) //起点
			{
				if(wh!=-a[l-1]) flag = 0;
			} 
			else
			{
				if(wh!=0) flag = 0;
			}
		}
		if(flag) cout<<"Yes\n";
		else cout<<"No\n";
	}
}
signed main(void)
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	T = 1;
	while(T--)
	solve();
	return 0;
}

你可能感兴趣的:(at,算法,c++,数据结构)