◆竞赛题目◆◇NOIP2015普及组◇求和

◇NOIP2015普及组◇求和


Description
一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。每个格子上都染了一种颜色color_i用[1,m]当中的一个整数表示),并且写了一个数字number_i。
这里写图片描述
定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
x、y、z是整数, x<y<zyx=zy
colorx=colorz
满足上述条件的三元组的分数规定为 (x+z)(numberx+numberz) 。整个纸带的分数规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10007所得的余数即可。

Input
第一行是用一个空格隔开的两个正整数n和m,n表纸带上格子的个数,m表纸带上颜色的种类数。
第二行有n用空格隔开的正整数,第i数字number表纸带上编号为i格子上面写的数字。
第三行有n用空格隔开的正整数,第i数字color表纸带上编号为i格子染的颜色。

Output
共一行,一个整数,表示所求的纸带分数除以10,007所得的余数。

Sample Input

输入样例#1:
6 2
5 5 3 2 2 2
2 2 1 1 2 1
输入样例#2: 
15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1

Sample Output

输出样例#1: 
82
输出样例#2:
1388

【输入输出样例 1 说明】
纸带如题目描述中的图所示。
所有满足条件的三元组为: (1,3,5),(4,5,6)
所以纸带的分数为 (1+5)(5+2)+(4+6)(2+2)=42+40=82

对于第 1 组至第 2 组数据, 1n100,1m5
对于第 3 组至第 4 组数据, 1n3000,1m100
对于第 5 组至第 6 组数据, 1n100000,1m100000 ,且不存在出现次数超过 20 的颜色;
对 于 全 部 10 组 数 据 , 1n100000,1m100000,1colorim1numberi100000


||题目解析||
从要求三元组的条件入手——移项得到 x+z=2y ,由于 x、y、z 都是整数,所以 x与z 必须同奇同偶(同奇同偶才能使它们的和为偶数)。因为 x<y<z ,所以只要 x、z 不越界,y 就一定不会越界。意思就是不用管 y 的值,那么我们就把原来的三元问题转换为了二元问题。正好,问题里的其他条件也只涉及 x 和 z ,那么我们的思路就是正解。
注意这是在同一种颜色中进行的,所以为了探寻其中规律,我们可以假设 集合A{ a1,a2,a3,...,an1,an } 为输入中某一同样颜色且同奇同偶的格子的编号,集合B{ b1,b2,b3,...,bn1,bn } 为输入中某一同样颜色且同奇同偶的格子标注的数字。即得与 a1 相关的项分数为:

(a1+a2)(b1+b2)+(a1+a3)(b1+b3)+...+(a1+an)(b1+bn)
=(n1)a1b1+(a1b2+a1b3+...+a1bn)+(a2b1+a3b1+...+anb1)+(a2b2+a3b3+...+anbn)
=(n1)a1b1+a1(b2+b3+...+bn)+b1(a2+a3+...+bn)+(a2b2+a3b3+...+anbn)

越写越像数论了……
再推,与 a2 相关的项分数为:

(a2+a3)(b2+b3)+(a2+a4)(b2+b4)+...+(a2+an)(b2+bn)
=(n2)a2b2+(a2b3+a2b4+...a2bn)+(a3b2+a4b2+...anb2)+(a3b3+a4b3+...+anbn)
=(n2)a2b2+a2(b3+b4+...+bn)+b2(a3+a4+...+an)+(a3b3+a4b4+...+anbn)

ai 相关的长这样….

(ai+ai+1)(bi+bi+1)+(ai+ai+2)(bi+bi+2)+...+(ai+an)(bi+bn)
=(ni1)aibi+(aibi+1+aibi+2+...+aibn)+(ai+1bi+ai+2bi+...+anbi)+(aibi+ai+1bi+1+...+anbn)
=(ni1)aibi+ai(bi+1+bi+2+...+bn)+bi(ai+1+ai+2+...+an)+(ai+1bi+1+ai+2bi+2+...+anbn)

整合一下,所有的分数应该是:

(n1)(a1b1+a2b2+...+an2bn2+an1bn1+anbn)
+a1(b2+b3+...+bN)+a2(b3+b4+...+bn)+...+an2(bn1+bn)+an1bn
+a2b1+a3(b1+b2)+...+an2(b1+b2+...+bn3)+an1(b1+b2+...+bn2)+an(b1+b2+...+bn1)

再合并一下下…

(n2)(a1b1+a2b2+...+an1nn1+anbn)+(a1+a2+...+an)(b1+b2+...+bN)

So…这么丑的通式何不用 “ ” 来简化一下?

(n2)ni=1(aibi)+ni=1aini=1bi

推理完了…(陷入数学的深渊 ~ ~o(>_<)o ~ ~ )
(成功从数学转入编程…)
如何用程序实现这些公式?当然不能每一次都计算一遍它们的和!于是想到用屡试不爽的前缀和!
首先我们需要一个存结果的int数组(ans),结合之前提到的按颜色和奇偶性分类,应这样定义:int ans[Max_m+5][2],即ans[i][j] 表示颜色为 i 且奇偶性为 j (1为奇数,0为偶数)的数的和,同时需要一个对应ans的int数组len[i][j] 表示颜色为 i 且奇偶性为 j 的格子的个数。这两个数组都可以在读入颜色时算出来,别忘了取模
最后定义一个int变量 Ans 存储答案。按照之前提到的通式求得Ans的值(最后水一下下


||程序样例||

/*Lucky_Glass*/
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int read() //读入优化走起
{
    int x=0;char ch=getchar();
    while(ch<'0' || ch>'9') ch=getchar();
    while('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
const int Mod=10007;
int num[100005],color[100005],ans[100005][2],len[100005][2];
int main()
{
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
        num[i]=read();
    for(int i=1;i<=n;i++)
    {
        int Color=color[i]=read();
        ans[Color][i%2]+=num[i];
        len[Color][i%2]++;
        ans[Color][i%2]%=Mod;
        len[Color][i%2]%=Mod;
    }
    long long Ans=0;
    for(int i=1;i<=n;i++)
        Ans+=(ans[color[i]][i%2]+(len[color[i]][i%2]-2)*num[i]%Mod)%Mod*i,Ans%=Mod;
    printf("%lld\n",Ans);
    return 0;
}

The End

Thanks for reading!

-Lucky_Glass


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值