题目传送门(内部题102)
输入格式
第一行三个正整数$n,k,q$,分别表示数列长度,操作长度和修改个数。
第二行$n$个数,表示给出的终止数列。
接下来$q$行,每行两个数$pos,dx$,表示将$a[pos]$加上$dx$,注意$dx$可能是负数。
输出格式
输出共有$q+1$行,分别是初始时和每次修改后的答案。如果凉宫可以取胜,输出$Yes$,否则输出$No$。
样例
样例输入:
5 2 5
1 1 1 2 1
3 −1
1 −1
3 1
3 1
1 −1
样例输出:
Yes
No
No
No
Yes
No
数据范围与提示
样例解释:
初始时,可以通过对$[1,2],[3,4],[4,5]$依次做$+1$操作得到;四次操作后,数列变为$[0,1,2,2,1]$,可以通过对$[2,3],[3,4],[4,5]$做$+1$操作得到。
数据范围:
对于$10\%$的数据,满足$n=1,q=0$。
对于$20\%$的数据,满足$nleqslant 5,q=10$。
对于$30\%$的数据,满足$nleqslant 18,q=10$。
对于$50\%$的数据,满足$nleqslant 2,000,qleqslant 2,000$。
对于$70\%$的数据,满足$nleqslant 100,000,qleqslant 100,000$。
对于$100\%$的数据,满足$kleqslant nleqslant 2 imes 10^6,qleqslant 2 imes 10^6$,保证任何时候,$|a[i]|,|dx|leqslant 10^9$。
题解
今晚是乱(mei)搞(lian)专题!
题目中的−是什么鬼?还好我眼尖一眼就看了出来。
首先,如果整个区间和不是$k$的倍数的话一定是$No$,然后我就发现大样例中$2000$组询问只有$4$个是$k$的倍数。
于是$n^2$暴力$+$剪枝直接$AC$。
时间复杂度:$Theta(omega n)$(其中$omega$为询问中区间和是$k$的倍数的个数)。
期望得分:$50$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int n,k,q;
long long sum;
int a[2000010],b[2000010],s[2000010],sss;
int main()
{
scanf("%d%d%d",&n,&k,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
if(!k)
{
q++;
while(q--)puts("No");
return 0;
}
if(sum%k){puts("No");goto nxt3;}
sss=0;
for(int i=1;i<=n-k+1;i++)
{
sss+=s[i];
b[i]+=a[i]-sss;
sss+=b[i];
s[i+k]-=b[i];
b[i]=0;
}
for(int i=n-k+2;i<=n;i++)
{
sss+=s[i];
b[i]+=a[i]-sss;
if(b[i]!=0){puts("No");goto nxt1;}
}
puts("Yes");
nxt1:for(int i=1;i<=n;i++)b[i]=s[i]=0;
nxt3:;
while(q--)
{
int pos,dx;
scanf("%d%d",&pos,&dx);
sum+=dx;a[pos]+=dx;
if(sum%k){puts("No");goto nxt4;}
sss=0;
for(int i=1;i<=n-k+1;i++)
{
sss+=s[i];
b[i]+=a[i]-sss;
sss+=b[i];
s[i+k]-=b[i];
b[i]=0;
}
for(int i=n-k+2;i<=n;i++)
{
sss+=s[i];
b[i]+=a[i]-sss;
if(b[i]!=0){puts("No");goto nxt2;}
}
puts("Yes");
nxt2:for(int i=1;i<=n;i++)b[i]=s[i]=0;
nxt4:;
}
return 0;
}
rp++