2018-12-02

原題太長,不好描述,貼鏈接:題面

解題思路

我們可以從題目中提取出的要點

要滿足體面所說三元組,需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]);
        }
    }
}

暴力枚舉顯然是玩不來的,但是我們可以通過暴力來找到幾點規(guī)律:

1.y-x = z-y --> 2*y = x+z -->即(x+z)肯定為偶數(shù),即x與z需同奇或同偶
2.y = (z+x)/2 -->即便x與z再大只要x,z<= n, y<n總成立,所以我們不用再枚舉y
3.既然每次必須滿足color[x]==color[z],那我們不妨在輸入的時候分類一下,這樣枚舉的時候同一個顏色只枚舉與之相同的顏色即可
4.既然x,z同奇或同偶,那我們不妨把奇數(shù)偶數(shù)頁分別分類一下

現(xiàn)在我們假設(shè)一個情況

    x1=1;x2=3;x3=5;且此時 color[x1] = color[x2] = color[x3];
    num[i] 為 x[i] 上標的數(shù)字
    那么他們的分數(shù)即為 (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])
    這個式子分兩部分 編號的和*每個塊上數(shù)字的和 + 這三塊各自的乘積的和
    當我們驗證多個式子后就會發(fā)現(xiàn)一個規(guī)律:
(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 = 要算分數(shù)的方塊數(shù)- 2
    這里是三塊 自然得出 k = 3 -2 成立,經(jīng)多次驗證n = 其他數(shù)時照樣成立

證明出以上結(jié)論來,此題應(yīng)該有些許眉目了

正確解法:

1.我們先把每個位置的方塊上的數(shù)字輸入到一個數(shù)組中 num[i] 表示 i 這個位置的數(shù)字
2.我們在輸入顏色的時候分類一下,具體做法是按照奇偶分類,前邊我們已經(jīng)得出最后的加和為(位置x累加和)*(每個x塊上的數(shù)字累加和)+(塊數(shù)p-2)*(每一塊的x*num[x]),所以我們記錄每個顏色的奇數(shù)位置累加和,和偶數(shù)位置累加和
3.最后枚舉過一遍顏色求出每種顏色的分數(shù)然后加和給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,因為這里是這個顏色奇數(shù)位置的塊的個數(shù),至少要兩個才行,(思考一下..)
        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]表示題目給出的每個塊上面的數(shù)字
a[0][x]表示顏色為 x 的塊且位置為偶數(shù)的位置累加和
a[1][x]表示顏色為 x 的塊且位置為奇數(shù)的位置累加和
b[0][x]表示顏色為 x 的塊且塊在偶數(shù)位置,塊上的數(shù)字的累加和
b[1][x]表示顏色為 x 的塊且塊在奇數(shù)位置,塊上的數(shù)組的累加和
c[0][x]表示顏色為 x 的塊,偶數(shù)位置的塊有多少個
c[1][x]表示顏色為 x 的塊,奇數(shù)位置的塊有多少個
d[0][x]表示顏色為 x 的塊,偶數(shù)位置i*g[i](自己乘自己)的累加和
d[0][x]表示顏色為 x 的塊,奇數(shù)位置i*g[i](自己乘自己)的累加和
*/

別忘在計算加和過程中%p就行

注意開 long long 不然AC代碼只過30%的數(shù)據(jù)

可以私聊交流一下其他做法,我覺得這應(yīng)該就是AC正解了,另外我寫了個暴力算法能過70%的數(shù)據(jù)

限于語文水平不行,可能證明比較繁瑣,如果可以的話希望可以私聊交流更簡潔的推導方法

#include<iostream>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容