牛客练习赛25 C 再编号

解题思路

我们先来观察一下题目中给出的公式

$$a'_i=(\sum_{j=1}^na_j)-a_i$$

通过这个公式推一下经过再编号后的序列的总和,因为我们推出这个和之后可以进行下一次计算。

$$\sum_{i=1}^na'_i=\sum_{i=1}^n((\sum_{j=1}^na_j)-a_i)$$

变形一下

$$\sum_{i=1}^na'_i=n\times (\sum_{j=1}^na_j)-\sum_{i=1}^na_i$$

$$\sum_{i=1}^na'_i=(n-1)\times \sum_{i=1}^na_i$$

emmmm,这个结论貌似很有用的样子,我们可以通过上面的推导预处理处每一次变化后整个序列的总和。

在观察一下原来的序列,每一次再编号他们的每个数和第一个数的差的绝对值是不变的。并且在奇数次的变化后为$a_1-a_j$,偶数次变化后是$a_j-a_1$。

既然是这样子,那我们就可以再通过之前预处理的总和在处理出每一次改变后的第一个值。通过这个值我们可以$O(1)$的对每一个位置上的数值进行询问。

这样的话总时间复杂度是$O(t)$的

 

代码看这里

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define LL long long
#define mod int(1e9+7)
LL a[100010],n,m,sum[100100];
LL ans[100001][2],num;
int main()
{
    LL x,t;
    scanf("%lld%lld%lld",&n,&m,&a[1]);
    num=a[1];
    for(int i=2;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        num+=a[i];
        sum[i]=a[1]-a[i];
    }
    ans[0][1]=a[1];
    for(int i=1;i<=100001;i++)
    {
        ans[i][1]=((num-a[1])+2*mod)%mod;
        a[1]=ans[i][1];
        num=(num*(n-1))%mod;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&x,&t);
        if(t%2!=0)printf("%lld\n",(ans[t][1]+sum[x]+mod)%mod);
        else printf("%lld\n",(ans[t][1]-sum[x]+mod)%mod);
    }
}

 

posted @ 2018-08-25 06:15  Mystical-W  阅读(195)  评论(0编辑  收藏  举报