【题解】QLU第二次测试赛——求和

原题太长,不好描述,贴链接:题面

解题思路

我们可以从题目中提取出的要点

要满足体面所说三元组,需x < y < z && y-x == z-y && color_x == color_z

首先我们考虑暴力的解法:

for(int y=1;y<=n;y++)
{
    for(int x=1;x<=n;x++)
    {
        for(int z=1;z<=n;z++)
        {
            if(x<y&&y<z&&(y-x)==(z-y)&&color[x]==color[z])
            sum+=(x+z)*(goal[x]+goal[z]);
        }
    }
}

暴力枚举显然是玩不来的,但是我们可以通过暴力来找到几点规律:

	1.y-x = z-y  -->  2*y = x+z  -->即(x+z)肯定为偶数,即x与z需同奇或同偶
	2.y = (z+x)/2 -->即便x与z再大只要x,z<= n, y<n总成立,所以我们不用再枚举y
	3.既然每次必须满足color[x]==color[z],那我们不妨在输入的时候分类一下,这样枚举的时候同一个颜色只枚举与之相同的颜色即可
	4.既然x,z同奇或同偶,那我们不妨把奇数偶数页分别分类一下

现在我们假设一个情况

	x1=1;x2=3;x3=5;且此时 color[x1] = color[x2] = color[x3];
	num[i] 为 x[i] 上标的数字
	那么他们的分数即为 (x1+x2)*(num[1]*num[2])+(x2+x3)*(num[2]*num[3])+(x1+x3)*(num[1]*num[3])
	我们把这个式子展开可得:
	x1*num[1]+x1*num[2]+x1*num[3]+x2*num[1]+x2*num[2]+x2*num[3]+x3*num[1]+x3*num[2]+x3*num[3]+x1*num[1]+x2*num[2]+x3*num[3]
	我们再把这式子合并一下:
	(x1+x2+x3)*(num[1]+num[2]+num[3])+(x1*num[1]+x2*num[2]+x3*num[3])
	这个式子分两部分 编号的和*每个块上数字的和 + 这三块各自的乘积的和
	当我们验证多个式子后就会发现一个规律:
(x1+x2+x3)*(num[1]+num[2]+num[3])+(x1*num[1]+x2*num[2]+x3*num[3]) == (x1+x2+x3)*(num[1]+num[2]+num[3])+k*(x1*num[1]+x2*num[2]+x3*num[3])
	这里的k=1;k是怎么来的呢 k = 要算分数的方块数- 2
	这里是三块 自然得出 k = 3 -2 成立,经多次验证n = 其他数时照样成立

证明出以上结论来,此题应该有些许眉目了

正确解法:

1.我们先把每个位置的方块上的数字输入到一个数组中 num[i] 表示 i 这个位置的数字
2.我们在输入颜色的时候分类一下,具体做法是按照奇偶分类,前边我们已经得出最后的加和为(位置x累加和)*(每个x块上的数字累加和)+(块数p-2)*(每一块的x*num[x]),所以我们记录每个颜色的奇数位置累加和,和偶数位置累加和
3.最后枚举过一遍颜色求出每种颜色的分数然后加和给sum就可以AC了
4.推导过程有点繁琐,我不知有没有更简洁的推导方法,其实虽然繁琐但并不复杂,同样AC代码更是简洁

以下贴出AC代码

#include<iostream>
#include<cstdio>
using namespace std;
long long a[2][100001];
long long b[2][100001];
long long c[2][100001];
long long d[2][100001];
long long g[100001];
long long n,m;
const int p = 10007;
int main()
{
    cin>>n>>m;
    for (int i=1;i<=n;i++)
    scanf("%lld",&g[i]);
    for (int i=1;i<=n;i++)
    {
        long long k;
        int j=i%2;   // 得出i位置的奇偶性
        scanf("%lld",&k);
        a[j][k]+=i;
        b[j][k]+=g[i];
        c[j][k]++;
        d[j][k]+=g[i]*i;
    }
    long long sum=0;
    for (int i=1;i<=m;i++)   //最后过一遍颜色,计算每个颜色的加和就ok
    {
        if(c[1][i]>1)     //至于为啥大于1,因为这里是这个颜色奇数位置的块的个数,至少要两个才行,(思考一下..)
        sum=(sum%p+(a[1][i]*b[1][i])%p+((c[1][i]-2)*d[1][i])%p)%p;
        if(c[0][i]>1)     //原因同上
        sum=(sum%p+(a[0][i]*b[0][i])%p+((c[0][i]-2)*d[0][i])%p)%p;
    }
    cout<<sum;
    return 0;
}

/*
这里给出注释:
g[x]表示题目给出的每个块上面的数字
a[0][x]表示颜色为 x 的块且位置为偶数的位置累加和
a[1][x]表示颜色为 x 的块且位置为奇数的位置累加和
b[0][x]表示颜色为 x 的块且块在偶数位置,块上的数字的累加和
b[1][x]表示颜色为 x 的块且块在奇数位置,块上的数组的累加和
c[0][x]表示颜色为 x 的块,偶数位置的块有多少个
c[1][x]表示颜色为 x 的块,奇数位置的块有多少个
d[0][x]表示颜色为 x 的块,偶数位置i*g[i](自己乘自己)的累加和
d[0][x]表示颜色为 x 的块,奇数位置i*g[i](自己乘自己)的累加和
*/

别忘在计算加和过程中%p就行

注意开 long long 不然AC代码只过30%的数据

可以私聊交流一下其他做法,我觉得这应该就是AC正解了,另外我写了个暴力算法能过70%的数据

限于语文水平不行,可能证明比较繁琐,如果可以的话希望可以私聊交流更简洁的推导方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值