原题解链接:https://ac.nowcoder.com/discuss/149978
定义 sum(a)=∑i=1nai ,考虑计算 sum(a′) 。
sum(a′)=i=1∑nai′=i=1∑n(sum(a)−ai)=(i=1∑nsum(a))−(i=1∑nai)=(n−1)sum(a)
定义 at(x) 表示经过 t 次再编号后第 x 个人的编号, sumt 表示 t 次再编号的编号和,
则当 t>0 时,有 at(x)=sumt−1−at−1(x) 。
对这个式子暴力展开,可得 at(x)=(∑i=0t−1(−1)isumt−1−i)+(−1)ta0(x) 。
因为 sumt=(n−1)sumt−1 ,所以左边是个公比 q 为 −(n−1) ,首项为 (−1)t−1sum0 的等比数列。
考虑等比数列求和公式,预处理 qi,(q−1)−1 就可以 O(1) 计算了。
实际上可以更暴力,预处理首项为 1 ,公比为 q 的等比数列的前缀和,用的时候乘上 (−1)t−1sum0 就好了。
时间复杂度 O(n+m+t) 。
#include<bits/stdc++.h>
using namespace std;
typedef long long s64;
#define rep(i,l,r) for(int i=l;i<=r;++i)
const int N=1e5+5,D=1e9+7;
int a[N];
s64 sum[N];
int main()
{
//freopen("1.in","r",stdin);
int n,m;
cin>>n>>m;
rep(i,1,n)scanf("%d",a+i);
int sum0=0;
rep(i,1,n)(sum0+=a[i])%=D;
s64 q=-(n-1),x=1;
sum[0]=x;
rep(i,1,N-1)
{
x=x*q%D;
sum[i]=(sum[i-1]+x)%D;
}
while(m--)
{
int x,t;
scanf("%d%d",&x,&t);
printf("%d\n",int(((-sum[t-1]*sum0+a[x])*(t%2?-1:1)%D+D)%D));
}
}