P2671 求和 题解

这道题有一点数学的味道,思路想清楚,代码其实并不难写。

由题意,满足条件的三元组 ( x , y , z ) (x,y,z) (x,y,z) 必须满足 y − x = z − y y-x=z-y yx=zy ,变形可得 x + z = 2 y x+z=2y x+z=2y ,又因为 x , y , z x,y,z x,y,z 都是整数,所以 x , z x,z x,z 同奇偶。又因为 c o l o r x = c o l o r z color_x=color_z colorx=colorz ,统计答案时也只需要 x , z x,z x,z ,所以其实最后和 y y y 没什么关系。

考虑到 c o l o r x = c o l o r z color_x=color_z colorx=colorz 并且 x , z x,z x,z 同奇偶,所以我们可以先将同一种颜色的格子归类(注意在存储 n u m b e r number number c o l o r color color 时,不要忘记存下原本的编号,我使用 u n d e r under under 表示),然后按照奇偶归类,最后统计答案。

如何统计答案呢?接下来是数学推导。

设最后归类之后,颜色相同且奇偶性相同的格子编号分别为 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an n u m b e r number number b 1 , b 2 , . . . , b n b_1,b_2,...,b_n b1,b2,...,bn N > 1 N > 1 N>1),令答案为 S S S ,有:

S = ( a 1 + a 2 ) ( b 1 + b 2 ) + ( a 1 + a 3 ) ( b 1 + b 3 ) + . . . + ( a 1 + a n ) ( b 1 + b n ) + ( a 2 + a 3 ) ( b 2 + b 3 ) + . . . + ( a 2 + a n ) ( b 2 + b n ) + . . . + ( a n − 1 + a n ) ( b n − 1 + b n ) S=(a_1+a_2)(b_1+b_2)+(a_1+a_3)(b_1+b_3)+...+(a1+a_n)(b_1+b_n)+(a_2+a_3)(b_2+b_3)+...+(a_2+a_n)(b_2+b_n)+...+(a_{n-1}+a_n)(b_{n-1}+b_n) S=(a1+a2)(b1+b2)+(a1+a3)(b1+b3)+...+(a1+an)(b1+bn)+(a2+a3)(b2+b3)+...+(a2+an)(b2+bn)+...+(an1+an)(bn1+bn)

= ∑ i = 1 n − 1 a i b i + a 1 ∑ i = 1 n b i − a 1 b 1 + a 2 ∑ i = 1 n b i − a 2 b 2 + . . . + a n ∑ i = 1 n b i − a n b n =\sum\limits_{i=1}^{n-1}a_ib_i+a_1\sum\limits_{i=1}^nb_i-a_1b_1+a_2\sum\limits_{i=1}^nb_i-a_2b_2+...+a_n\sum\limits_{i=1}^nb_i-a_nb_n =i=1n1aibi+a1i=1nbia1b1+a2i=1nbia2b2+...+ani=1nbianbn

= ∑ i = 1 n − 2 a i b i + ∑ i = 1 n a i × ∑ i = 1 n b i =\sum\limits_{i=1}^{n-2}a_ib_i+\sum\limits_{i=1}^na_i\times\sum\limits_{i=1}^nb_i =i=1n2aibi+i=1nai×i=1nbi(如果以上几步不能理解,建议手动推导一遍或者是取特殊值找规律)

  • N=1时, S = − a 1 b 1 + a 1 b 1 = 0 S=-a_1b_1+a_1b_1=0 S=a1b1+a1b1=0 ,不会有影响。

这就好办了!分类完之后,统计这些答案我们可以直接 O ( n ) O(n) O(n) 扫一遍即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000+10,P=10007;
typedef long long LL;
LL n,m,ji[MAXN],ou[MAXN],ans; 
struct node
{
 LL number,color,under;
}a[MAXN];//结构体存储 
bool cmp(const node &fir,const node &sec)
{
 if(fir.color!=sec.color) return fir.color<sec.color;
 return fir.under<sec.under;
}
int main()
{
 scanf("%d %d",&n,&m);
 for(int i=1;i<=n;i++) a[i].under=i;//处理下标 
 for(int i=1;i<=n;i++) scanf("%d",&a[i].number);
 for(int i=1;i<=n;i++) scanf("%d",&a[i].color);
 sort(a+1,a+n+1,cmp);//按颜色分类 
 for(int i=1;i<=n;i++)
 {
  if(a[i].under&1) ji[++ji[0]]=i;
  else ou[++ou[0]]=i;
 }//按奇偶分类 
 LL sgmai=a[ji[1]].under%P,sgmbi=a[ji[1]].number%P,sgmab=a[ji[1]].under*a[ji[1]].number%P,ls=a[ji[1]].color,cnt=1;
 for(int i=2;i<=ji[0];i++)
 {
  if(a[ji[i]].color!=ls)
  {
   ans=(ans+sgmai*sgmbi%P+(cnt-2)*sgmab%P)%P;
   sgmai=a[ji[i]].under%P;
   sgmbi=a[ji[i]].number%P;
   sgmab=a[ji[i]].under*a[ji[i]].number%P;
   ls=a[ji[i]].color;
   cnt=1;
  }
  else
  {
   cnt++;
   sgmai=(sgmai+a[ji[i]].under)%P;
   sgmbi=(sgmbi+a[ji[i]].number)%P;
   sgmab=(sgmab+a[ji[i]].under*a[ji[i]].number%P)%P;
  }
 }//统计奇数答案,sgmai为ai的和,sgmbi为bi的和,sgmab为ai*bi的和,ls表示当前处理的颜色,cnt为个数。 
 ans=(ans+sgmai*sgmbi%P+(cnt-2)*sgmab%P)%P;//千万不要忘记在扫完后统计最后答案!!!否则会漏掉最后一个颜色 
 sgmai=a[ou[1]].under%P,sgmbi=a[ou[1]].number%P,sgmab=a[ou[1]].under*a[ou[1]].number%P,ls=a[ou[1]].color,cnt=1;
 for(int i=2;i<=ou[0];i++)
 {
  if(a[ou[i]].color!=ls)
  {
   ans=(ans+sgmai*sgmbi%P+(cnt-2)*sgmab%P)%P;
   sgmai=a[ou[i]].under%P;
   sgmbi=a[ou[i]].number%P;
   sgmab=a[ou[i]].under*a[ou[i]].number%P;
   ls=a[ou[i]].color;
   cnt=1;
  }
  else
  {
   cnt++;
   sgmai=(sgmai+a[ou[i]].under)%P;
   sgmbi=(sgmbi+a[ou[i]].number)%P;
   sgmab=(sgmab+a[ou[i]].under*a[ou[i]].number%P)%P;
  }
 }//同理 
 ans=(ans+sgmai*sgmbi%P+(cnt-2)*sgmab%P)%P;
 printf("%d\n",ans);
 return 0;
}

一个比较容易犯的错误:这道题虽然模数 P = 10007 P=10007 P=10007 ,但是在处理 ∑ i = 1 n − 2 a i b i \sum\limits_{i=1}^{n-2}a_ib_i i=1n2aibi 时,由于 a i a_i ai 的最大值为 N N N 1 ≤ N ≤ 100000 1 \leq N \leq 100000 1N100000), b i b_i bi 的最大值为 n u m b e r i number_i numberi 的最大值( 1 ≤ n u m b e r i ≤ 100000 1 \leq number_i \leq 100000 1numberi100000),所以在处理 ∑ i = 1 n − 2 a i b i \sum\limits_{i=1}^{n-2}a_ib_i i=1n2aibi 时中间过程可能会有溢出,所以最好开 long long 存储,避免数据溢出。

总结:诸如这一类的数学题目,码量一般不是很大,关键是如何利用题目条件进行推导,不断优化算法(这里就需要比较扎实的数学基础)最后达到满分。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值