洛谷 P2671 求和 解题报告

P2671 求和

题目描述

一条狭长的纸带被均匀划分出了\(n\)个格子,格子编号从\(1\)\(n\) 。每个格子上都染了一种颜色\(color_i\)\([1,m]\)当中的一个整数表示),并且写了一个数字\(number_i\)

定义一种特殊的三元组:\((x,y,z)\),其中\(x,y,z\)都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:

\(xyz\)是整数, \(x<y<z,y-x=z-y\)

\(color_x=color_z\)

满足上述条件的三元组的分数规定为\((x+z)×(number_x+number_z)\) 。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。

输入输出格式

输入格式:

第一行是用一个空格隔开的两个正整数\(n\)\(m,n\)表纸带上格子的个数,\(m\)表纸带上颜色的种类数。

第二行有\(n\)用空格隔开的正整数,第\(i\)数字\(number\)表纸带上编号为\(i\)格子上面写的数字。

第三行有\(n\)用空格隔开的正整数,第\(i\)数字\(color\)表纸带上编号为\(i\)格子染的颜色。

输出格式:

一个整数,表示所求的纸带分数除以10007所得的余数。

说明

纸带如题目描述中的图所示。

所有满足条件的三元组为: (1,3,5),(4,5,6) 。

所以纸带的分数为(1+5)×(5+2)+(4+6)×(2+2)=42+40=82 。

对于第1组至第2组数据,1≤n≤100,1≤m≤5 ;

对于第3组至第4组数据, 1≤n≤3000,1≤m≤100 ;

对于第5组至第6组数据, 1≤n≤100000,1≤m≤100000 ,且不存在出现次数超过20的颜色;

对 于 全 部10组 数 据 ,1≤n≤100000,1≤m≤100000,1≤color_i≤m,1≤number_i≤100000


这题教会了我$ \sum $的化简。

我们发现,奇偶位相同时颜色相同的都可以产生贡献,在一个奇偶性的某一个同样颜色的块的答案为

\(\sum_{i=1}^n \sum_{j=i+1}^n (x_i+x_j)*(y_i+y_j)\) \(x_i\)为数字,\(y_i\)为位置。

需要\(O(n)\)复杂度算出它

化简前,先补充一下$\sum $的有关知识

  1. 优先级比四则运算符低
  2. \(\sum_{i=1}^n a_i+b_i \Leftrightarrow \sum_{i=1}^n a_i+\sum_{i=1}^n b_i\)
  3. \(\sum_{i=1}^n r*a_i \Leftrightarrow r*\sum_{i=1}^n a_i\)
  4. \(\sum_{i=1}^n \sum_{j=1}^n a_{ij} \Leftrightarrow \sum_{j=1}^n \sum_{i=1}^n a_{ij}\)


\(\sum_{i=1}^n \sum_{j=i+1}^n (x_i+x_j)*(y_i+y_j)\)
\(=\sum_{i=1}^n \sum_{j=i+1}^n x_i*y_i+x_i*y_j+x_j*y_i+x_j*y_j\)
\(=\sum_{i=1}^n \sum_{j=i+1}^n x_i*y_i+\sum_{i=1}^n \sum_{j=i+1}^n x_j*y_j+\sum_{i=1}^n \sum_{j=i+1}^n x_j*y_i+\sum_{i=1}^n \sum_{j=i+1}^n x_i*y_j\)
\(=\sum_{i=1}^n (n-i)*x_i*y_i+\sum_{i=1}^n (i-1)*x_i*y_i+\sum_{i=1}^n y_i \sum_{j=i+1}^n x_j+\sum_{i=1}^n x_i \sum_{j=i+1}^n y_j\)
\(=(n-1)\sum_{i=1}^n x_i*y_i+\sum_{i=1}^n y_i \sum_{j=i+1}^n x_j+\sum_{i=1}^n x_i \sum_{j=i+1}^n y_j\)

先处理出前缀和维护即可


Code:

#include <cstdio>
#include <algorithm>
#define ll long long
const ll N=50010;
const ll mod=10007;
ll n,m,cnta,cntb,fa[21],fb[21];
struct node
{
    ll color,num,pos;
    bool friend operator <(node n1,node n2)
    {
        return n1.color<n2.color;
    }
}a[N],b[N];
int main()
{
    scanf("%d%d",&n,&m);
    ll num,color,ans=0;
    for(ll i=1;i<=n;i++)
    {
        scanf("%d",&num);
        if(i&1) a[++cnta].num=num%mod,a[cnta].pos=i%mod;
        else b[++cntb].num=num%mod,b[cntb].pos=i%mod;
    }
    for(ll i=1;i<=n;i++)
    {
        scanf("%d",&color);
        if(i&1) a[i+1>>1].color=color;
        else b[i+1>>1].color=color;
    }
    std::sort(a+1,a+1+cnta);
    std::sort(b+1,b+1+cntb);
    for(ll i=1;i<=cnta;)
    {
        color=a[i].color;
        ll tmp=i,cnt=0;
        while(a[i].color==color)
        {
            cnt++;
            fa[cnt]=(a[i].pos+fa[cnt-1])%mod;
            fb[cnt]=(a[i].num+fb[cnt-1])%mod;
            i++;
        }
        for(ll j=1;j<=cnt;j++)
        {
            ll t=j+tmp-1;
            ans=(ans+(cnt-1)*a[t].pos%mod*a[t].num%mod
                +((fb[cnt]-fb[j])%mod*a[t].pos
                +(fa[cnt]-fa[j])%mod*a[t].num)%mod)%mod;
        }
    }
    for(ll i=1;i<=cntb;)
    {
        color=b[i].color;
        ll tmp=i,cnt=0;
        while(b[i].color==color)
        {
            cnt++;
            fa[cnt]=(b[i].pos+fa[cnt-1])%mod;
            fb[cnt]=(b[i].num+fb[cnt-1])%mod;
            i++;
        }
        for(ll j=1;j<=cnt;j++)
        {
            ll t=j+tmp-1;
            ans=(ans+(cnt-1)*b[t].pos%mod*b[t].num%mod
                +((fb[cnt]-fb[j])*b[t].pos%mod
                +(fa[cnt]-fa[j])*b[t].num%mod)%mod)%mod;
        }
    }
    printf("%d\n",ans);
    return 0;
}

posted @ 2018-06-29 15:04  露迭月  阅读(399)  评论(0编辑  收藏  举报