求和(NOIP2015)

来源:互联网 发布:jsp声明调用java类 编辑:程序博客网 时间:2024/06/06 19:00

题目链接:求和
这道题不是很简单,因为数据并不是很小,常规计算会t。
这里引用chenleyu的解答(如果想要cgg原创解答,……改天吧):
这题相对是比较难的,首先我们要解读题目的意思

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

由这段不难得到,所谓纸带,其实就是一个集合组,每一个小集合(格子)里都有三个元素:编号,颜色和上面写的数

就是这样

纸带[]

|num,col,i|num,col,i|num,col,i||num,col,i||num,col,i||num,col,i|
然后我们再来看那神奇的三元组

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

1.xyz是整数,x小于y小于z,y-x=z-y

2.colorx=colorz

满足上述条件的三元组的分数规定为(x+z)*(number_x+number_z)”

我们看三元组的第一个条件

首先x小于y小于z这很容易理解,我们来看y-x=z-y

通过等式的性质,我们可以将它进行一些变换

y-x=z-y

y+y=z+x

z+x=2y

这样就可以知道z+x必为偶数,那又因为

奇数+奇数=偶数

偶数+偶数=偶数

奇数+偶数=奇数

所以x和z的奇偶性一定相同

所以题目三元组的条件就可以化为

1 z>x

2 z和x的奇偶性相同

3 z格和x格的颜色相同

(跟y一点关系也没有)

换句话说,只要有两个数奇偶性相同,颜色相同,那他们必是会产生分数的

再来看分数的计算

分数=(x+z)*(num[x]+num[z])

我们再来做一点变换

根据乘法分配律

(x+z)*(num[x]+num[z])

=x*num[x]+x*num[z]+z*num[x]+z*num[z]

那假设i1,i2,i3,i4….的奇偶性相同,颜色相同,那么

他们的得分就为

(i1*num[i1]+i1*num[i2]+i2*num[i1]+i2*num[i3])+(i1*num[i1]+i1*num[i3]+i3*num[i1]+i3*num[i3])+…………..

把括号去掉,把和i1有关的放在一起,把和in有关的放在一起

就成了这样

i1*num[i1]+i1*num[i2]+ i1*num[i1]+i1*num[i3]+…….(和i1有关的)

=i1*(num[i1]+num[i2]+…….+num[in])+n*(i1*num[i1])

于是我们就可以得到这个公式

和in有关的得分就

= in*(num[i1]+num[i2]+…….+num[in])+n*(in*num[in])

再把i1,i2,i3….in的得分加起来就是总分了

因为结果很大所以要记得边做边%10007哦
看得出来,他讲得很详细,我相信你也应该能看懂了,下面看我的代码:

#include<bits/stdc++.h>#ifdef WIN32                  //1#define LL "%I64d"#else#define LL "%lld"#endifusing namespace std;int n,c;int sum[2][100001]={0};int d[2][100001]={0};int num[100001];int col[100001];long long maxx=0;int main(){    scanf("%d%d",&n,&c);    for (int i=1;i<=n;i++){        scanf("%d",&num[i]);        num[i]%=10007;        }    int n1=0,n2=0;    for (int i=1;i<=n;i++){        scanf("%d",&col[i]);        sum[i%2][col[i]]+=num[i];       //2            sum[i%2][col[i]]%=10007;        d[i%2][col[i]]++;            }    for (int i=1;i<=n;i++){        maxx+=1LL*i%10007*((sum[i%2][col[i]]+(d[i%2][col[i]]-2)%10007*num[i]+10007)%10007);   //3        maxx%=10007;            }    printf(LL,maxx);    return 0;}

讲三点(这里是cgg原汁原味的讲解):
1处:这里是cgg曾在信息学培训中,提到过的技巧。
2处:这里是计算每一种颜色单数下标和偶数下标的前缀和。
3处:套公式。

原创粉丝点击