求和

Problem description

问题描述

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

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

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

Input format

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

Output format

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

Algorithm design

Simple enumeration + Mathematics deal

Problem analysis

核心:数据分离

N太大 直接搞O(N2)

读题

x<y<z,y-x=z-y,colorx=colorz
翻译一下

x,z奇偶性相同且同种颜色

那么把n拆成两条链:奇数链,偶数链,两链互不相干

对于链上所有同种颜色的点 都可以求分数

既然如此再看

(x+z)*(number_x+number_z)

拆解后

x*num_x+z*num_z+x*num_z+z*num_x

前缀和思想

取一点x 那么关于x的所有三元组的分数之和

x*num_x*cnt_others + sumcnt_others + x*numcnt_others + num_x*idcnt_others

所以只需要分两条链

枚举每个点

根据其颜色进行处理

O(2n)

Anyway

把cnt处理完了再搞会有一倍冗出

所以边枚举边搞最好

先前忘了这点愣了几分钟

 

错误记录

1.没把ans求余

2.没考虑sum也很大也要求余

3.即使执行上述操作 sum还是很大 所以开ll

Source code

 1 #include <bits/stdc++.h>
 2 #define F(i,j,k) for(int i=j;i<=k;i++)
 3 #define D(i,j,k) for(int i=j;i>=k;i--)
 4 #define sc(i) scanf("%lld",&i)
 5 #define mo 10007
 6 #define ll long long
 7 #define R return
 8  
 9 using namespace std;
10  
11 int n,m;
12 llans,num[100010],col[100010],sumnu[100010],sum[100010],sumid[100010],cnt[100010];
13  
14 void read()
15 {
16    cin>>n>>m;
17    F(i,1,n)sc(num[i]);
18    F(i,1,n)sc(col[i]);
19    R;
20 }
21  
22 void work()
23 {
24    F(jff,1,2)
25    {
26       memset(sumid,0,sizeof(sumid));
27       memset(sumnu,0,sizeof(sumnu));
28       memset(sum,0,sizeof(sum));
29       memset(cnt,0,sizeof(cnt));
30       for(int i=jff;i<=n;i+=2)
31       {
32          ans=(ans+sum[col[i]]+num[i]*i*cnt[col[i]])%mo;
33          ans=(ans+sumnu[col[i]]*i)%mo;
34          ans=(ans+sumid[col[i]]*num[i])%mo;
35 //通过前缀和计算 将结果数添加
36          sumid[col[i]]=(sumid[col[i]]+i)%mo;
37          sumnu[col[i]]=(sumnu[col[i]]+num[i])%mo;
38          sum[col[i]]=(sum[col[i]]+num[i]*i)%mo;
39 //像前面说的边推进边处理所有前缀和
40       }
41    }
42    cout<<ans<<endl;
43    R;
44 }
45  
46      
47  
48 int main()
49 {
50    freopen("sum.in","r",stdin);
51    freopen("sum.out","w",stdout);
52    read();
53    work();
54    R 0;
55 }
56  
View Code

over

转载于:https://www.cnblogs.com/qswx/p/9155674.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值