题解 P2671 【求和】

· · 题解

很简单的一道数学题,楼下的代码为什么都那么长,看起来好复杂

题目分析

根据题目,我们可以设有三个下标,他们分别是x,y,z,要满足x<y<z且y-x=z-y

所以我们可以模拟x,y,z,其时间复杂度为O(n^3),由于n<=100000所以一定会超时

但这个方法是可以优化的

由此我们可以得到2y=z+x

由此可知z+x必须是一个偶数即z,x同为奇数或同为偶数

所以我们其实只要穷举x和z就行了,但这个方法的时间复杂度为O(n^2)所以还是会超时

我们可以用一下分组思想,把每个颜色分为一组,再在每个颜色中按奇偶分组,所以一共有2m组

设一个分组里有k个数,这个分组中的数分别是x[1],x[2]……x[k],下标分别是y[1],y[2]……y[k]

那么可得

答案=(x[1]+x[2])*(y[1]+y[2])+(x[1]+x[3])*(y[1]+y[3])+……+(x[1]+x[k])*(y[1]+y[k])

+(x[2]+x[3])*(y[2]+y[3])+(x[2]+x[4])*(y[2]+y[4])+……+(x[2]+x[k])*(y[2]+y[k])

+……

   +(x[k-1]+x[k])\*(y[k-1]+y[k])

   =x[1]\*(y[1]+y[2]+y[1]+y[3]+……+y[1]+y[k])

   +x[2]\*(y[1]+y[2]+y[2]+y[3]+……+y[2]+y[k])

+……

   +x[k]\*(y[1]+y[k]+y[2]+y[k]+……+y[k-1]+y[k])

   =x[1]\*(y[1]\*(n-2)+y[1]+y[2]+……+y[k])

   +x[2]\*(y[2]\*(n-2)+y[1]+y[2]+……+y[k])

+……

   +x[k]\*(y[k]\*(n-2)+y[1]+y[2]+……+y[k])

然后事先将y[1]+y[2]+……+y[k]求出,用的时候调用就行了,其时间复杂度为O(n)

代码如下:

//--新阶梯工作室防伪水印-- 
//--By新阶梯工作室 闪现--
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>//头文件准备
using namespace std;
int s[100005][2],sum[100005][2],c[100005],x[100005];.//定义二维数组方便分组
int n,m,ans;
int main(){
    scanf ("%d %d",&n,&m);//其实m没有什么用处
    for (int i=1;i<=n;i++){
        scanf ("%d",&x[i]);
    }
    for (int i=1;i<=n;i++){
        scanf ("%d",&c[i]);
        s[c[i]][i%2]++;//求出这个分组中有多少个数
        sum[c[i]][i%2]=(sum[c[i]][i%2]+x[i])%10007;//事先求出累加和,注意,要mod10007
    }
    for (int i=1;i<=n;i++){
        ans=(ans+i*((s[c[i]][i%2]-2)*x[i]%10007+sum[c[i]][i%2]))%10007;//依次然后代入,注意,也要mod10007
    }
    printf ("%d\n",ans);//最后输出
    return 0;
}