链接:https://ac.nowcoder.com/acm/problem/16492
来源:牛客网
题目描述
一条狭长的纸带被均匀划分出了 n 个格子,格子编号从 1 到 n 。每个格子上都染了一种颜色 color[i](用 [1,m] 当中的一个整数表示),并且写了一个数字 number[i] 。
定义一种特殊的三元组: (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 格子染的颜色。
输出描述:
共一行,一个整数,表示所求的纸带分数除以10,007所得的余数。
分析:
这题主要有两个点:
- 题目要求y-x=z-y,化简即为x+z=2y,故x+z的值为偶数,易得x和z奇偶性相同,这样x和z之和才能为偶数,且颜色必须相同才能凑成一个规范的三元组;
- 分析数学规律。假设有a,b两个颜色相同的偶数格子,那么a和b就能凑成一个三元组;如果有a,b,c三个颜色相同的偶数格子,那么a和b,a和c以及b和c都能凑成三元组,这样就有三个三元组,那么根据这个规律,猜测它们的表达式之间会有某种联系。下面来推导相应的表达式:当只有a、b时,其对应的值为aa和bb,这个三元组的分数为(a+b)*(aa+bb)=0*(a*aa+b*bb)+(a+b)*(aa+bb);当有a、b、c时,分数为(a+b)*(aa+bb)+(a+c)*(aa+cc)+(b+c)*(bb+cc)=1*(a*aa+b*bb+c*cc)+(a+b+c)*(aa+bb+cc);当有a、b、c、d时,分数为(a+b)*(aa+bb)+(a+c)*(aa+cc)+(a+d)*(aa+dd)+(b+c)*(bb+cc)+(b+d)*(bb+dd)+(c+d)*(cc+dd)=2*(a*aa+b*bb+c*cc+d*dd)+(a+b+c+d)*(aa+bb+cc+dd)。易得表达式规律,分数=(符合条件的格子数-2)*(格子序号与格子值乘积之和)+(格子序号和)*(格子值之和)。
综上,我们要将所有的记录分成两组,一组为格子序号为奇数,一组格子序号为偶数,且同时记录对应的格子值和格子颜色。故用三维数组color[i][0][1]记录颜色为i的偶数序号格子的序号和,color[i][0][1]为颜色为i的奇数序号格子序号和,color[i][1][]记录颜色为i的格子的数字和,color[i][2][]记录颜色为i的格子序号与格子值乘积之和,同时用二维数组cnt[i][]记录颜色为i的奇偶格子总数。
代码:
#include <bits/stdc++.h>
//数学题 化简计算表达式以找到对应规律
using namespace std;
const int mod =10007,N=100005;
int color[N][3][2],a[N][2],cnt[N][2];
int n,m,sum,x;
int main()
{
scanf("%d %d",&n,&m);
for(int i=0;i<2;i++){
for(int j=1;j<=n;j++)scanf("%d",&a[j][i]);
}
for(int i=1;i<=n;i++){
x=i%2;
cnt[a[i][1]][x]++;
color[a[i][1]][0][x]+=i;//格子序号和
color[a[i][1]][1][x]+=a[i][0];//格子数字和
color[a[i][1]][2][x]+=1ll*i*a[i][0]%mod;//格子序号与数字乘积之和
}
for(int i=1;i<=m;i++){
for(int j=0;j<2;j++){
sum+=1ll*color[i][0][j]*color[i][1][j]%mod+1ll*(cnt[i][j]-2)*color[i][2][j]%mod;
sum%=mod;
}
}
printf("%d\n",sum);
return 0;
}