1. 程式人生 > >2017年湖南多校對抗賽第12場_J_數字和

2017年湖南多校對抗賽第12場_J_數字和

Title:

長者對小明施加了膜法,使得小明每天起床就像馬丁的早晨一樣。 今天小明早上起來後發現身體雖然變小,頭腦依舊不變變傻。

他有一條紙帶,上面有n個數字,第i個數字為Ai。 他想把紙帶選三個位置p1, p2, p3(p1 < p2 < p3)把紙帶剪成4個每條長度至少為1的4條紙帶。 分別為[1, p1-1], [p1+1, p2-1], [p2+1, p3-1], [p3+1, n],使得4個部分中數字之和相等。

Input

多組輸入 每組測試資料第一行輸入一個n(7 ≤ n ≤ 105) 第二行n個數,第i個數為Ai(0 ≤ Ai ≤ 109),表示第i個數

Output

輸出字典序最小的p1,p2,p3 如果不存在這種操作,輸出-1

Sample Input

7
6 2 6 2 6 2 6
7
1 2 3 4 5 6 7

Sample Output

2 4 6
-1

思路:

   (1)剛開始是準備列舉兩個點的,就是Left,Right去尋找兩個點,找到了之後就相當於把資料劃分成兩段了,通過前後的值,查詢第三個是否存在,就可以AC掉了。(存在特殊情況,全部為0的情況,特殊判斷,再次WA了2發。)

    (2)第一個思路WA了兩發之後,想到全為0的情況,答案錯誤,開始第二種思路,列舉第一個點,通過第一個點開始尋找第二個點,依次尋找第三個點,最後得到結果。(在此,將全為0的情況特殊判斷一下,第一個也過了。)

兩端列舉AC:

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

long long int temp[100005],sum[100005],k;
int p1,p2,p3,t;

int main()
{
    while(scanf("%d",&t)!=EOF)
    {
        sum[0] = 0;
        ///儲存資料
        for(int rest = 1; rest<=t; rest++){
            scanf("%lld",&temp[rest]);
            sum[rest] = temp[rest] + sum[rest-1];
        }
         if(sum[t] == 0){
            printf("2 4 6\n");
            continue;
        }
        ///求某一個點,突破
        int Left = 2,Right = t-1;
        bool sign =false;
        while(true)
        {
            while(Left <= Right && sum[Left-1] != (sum[t] - sum[Right]))
            {
                if(sum[Left - 1] < sum[t] - sum[Right]){
                    Left++;
                }else{
                    Right--;
                }
            }
            if(Left > Right){
                printf("-1\n");
                break;
            }
            for(int rest = Left+1 ; rest < Right;rest++){
                    ///前面一部分的和為:1~(Left-1)
                if(sum[Left - 1] == (sum[rest] - sum[Left]-temp[rest])  && (sum[Right] - sum[rest] - temp[Right]) == sum[Left - 1]  ){
                    printf("%d %d %d\n",Left,rest,Right);
                    sign = true;
                    break;
                }
            }
            if(sign)
                break;
            Left++,Right--;
        }
    }
    return 0;
}

一端列舉AC:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>
using namespace std;

long long temp[100005],sum[100005];
map<long long ,int> flag;

int main()
{
    int t,Left;
    while(scanf("%d",&t)!=EOF)
    {
        flag.clear();
        sum[0] = 0;
        ///儲存資料
        for(int rest = 1; rest<=t; rest++){
            scanf("%lld",&temp[rest]);
            sum[rest] = temp[rest] + sum[rest-1];
            flag[ sum[rest] ] = rest;
        }
        if(sum[t] == 0){
            printf("%d %d %d\n",2,4,6);
            continue;
        }
        ///求某一個點,突破
        for( Left=2;Left <= t-3;Left++)
        {
            int NowSum = sum[Left-1];
            if(flag[  NowSum*2 + temp[Left] ] == 0)
                continue;
            int p2 = flag[  NowSum*2 + temp[Left] ] + 1;
            if( flag[ sum[p2] + NowSum ] == 0)
                continue;
            int p3 = flag[ sum[p2] + NowSum ] + 1 ;

            if( NowSum*4 + temp[p2] + temp[Left] + temp[p3]  == sum[t]){
                printf("%d %d %d\n",Left,p2,p3);
                break;
            }
        }
        if(Left > t-3 ) printf("-1\n");
    }
    return 0;
}