【SSL 1235】【NOIP2015 普及组】求和(数学解法)

题目大意

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

   

(这图不用想,也是从SSL学校网站上抠下来的)

       定义一种特殊的三元组:(x,y,z),其中 x,y,z 都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:
   1. x,y,z是整数,x<y<z,y−x=z−y 
   2. color_x=color_z

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

输入格式

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

1<=n<=1e5,1<=color_i<=m<=1e5,1<=number_i<=1e5

输出格式

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

 输入样例

 【输入样例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

输出样例

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


【输入样例2】
1388

基本思路

这题暴力不用说,必超。下面我们来看看数学解法具体是什么样的。

//推导:

y-x=z-y         2*y=x+z        x+z为偶数,所以x,z同奇偶

同色同奇偶(可以运算)的格子

P1 P2 P3 P4 (下标i)

X1 X2 X3 X4 (number_i)

S=X1+X2+X3+X4         k=4(有几个格子)

ans= (P1+P2)*(X1+X2)+(P1+P3)*(X1+X3) +(P1+P4)*(X1+X4)+(P2+P3)*(X2+X3) +(P2+P4)*(X2+X4)+(P3+P4)*(X3+X4)

乘法分配

=P1*(3*X1+X2+X3+X4)+P2*(X1+3*X2+X3+X4) +P3*(X1+X2+3*X3+X4)+P4*(X1+X2+X3+3*X4) 

=P1*S+P1*2*X1+P2*S+P2*2*X2 +P3*S+P3+2+X3+P4*S+P4*2*X4

Pi*S+Pi*(k-2)*Xi

这题说实话没点观察力是真想不出来。

核心代码

思路注释上去了,去掉注释应该也就二十多行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//推导:
//y-x=z-y
//2*y=x+z
//x+z为偶数,所以x,z同奇偶 
//同色同奇偶(可以运算)的格子
//P1 P2 P3 P4
//X1 X2 X3 X4
//S=X1+X2+X3+X4
//k=4(有几个格子) 
//ans=
//(P1+P2)*(X1+X2)+(P1+P3)*(X1+X3)
//+(P1+P4)*(X1+X4)+(P2+P3)*(X2+X3)
//+(P2+P4)*(X2+X4)+(P3+P4)*(X3+X4)
//
//=P1*(3*X1+X2+X3+X4)+P2*(X1+3*X2+X3+X4)
//+P3*(X1+X2+3*X3+X4)+P4*(X1+X2+X3+3*X4)
//
//=P1*S+P1*2*X1+P2*S+P2*2*X2
//+P3*S+P3+2+X3+P4*S+P4*2*X4
//
//Pi*S+Pi*(k-2)*Xi
const ll mod=10007;
const ll N=1e5+10;
ll n,m,ans,s[N][2],x[N],k[N][2],c[N];
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>x[i];
	for(int i=1,ci;i<=n;i++){
		cin>>c[i];
		s[c[i]][i%2]+=x[i];
		s[c[i]][i%2]%=mod;//同余定理
		k[c[i]][i%2]++;
	}
	for(int p=1;p<=n;p++){
		if(k[c[p]][p%2]<2) continue;
		ans+=p*s[c[p]][p%2]+p*(k[c[p]][p%2]-2)*x[p];
		ans%=mod; 
	}
	cout<<ans;
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值