1. 程式人生 > 其它 >[Acwing藍橋杯貪心] 1248. 靈能傳輸

[Acwing藍橋杯貪心] 1248. 靈能傳輸

題目:1248. 靈能傳輸 - AcWing題庫

大概題意:給一個長度為數列,除了兩個端點以外,任意選一個點,可以將該點的值分給相鄰的兩個點,也可以得到相鄰的兩個點的值

整個數列的總能量不變  就是能量輸出給相鄰的點或者從相鄰的點輸入。

分析:

這是一個貪心題,時間複雜度 倒不是問題 關鍵點是思路

這個題有三個難點,不太好想的地方:

設 每個點的元素 都存在 陣列a[ ] 中

1、要考慮到字首並且探究到字首和的規律

規律:

假設這個陣列的字首和為:  s[1], s[2] ... s[n] 

如果 點 i 的能量與相鄰的點 i - 1 和 i +1 傳遞 那麼 就是  a[ i ] -= 2 * a[ i ] , a[ i-1] += a[ i ] , a[ i+1] += a[ i ] ;//適應於a[ i ]無論正負

那 麼 s [ i+1]大小是沒有變的 ,s [ i - 1] 多了個 a[ i ] , s [ i ] 減去了兩個 a [ i ] , 相當於 減去相對多出的一個a[ i ],又少了個a[ i ]

s [ i-1] 變成了 s[ i ] , s[ i ] 變成了 s[ i-1]

對應到函式上就是 除了起始的點兩個點不能交換 最後面的兩個點不能交換 任意的兩個 a[ i ]和a[ i-1]可以互換。

2、因為開始的起點不變,最後的終點不能變

這裡用了貪心的思想

那麼當圖形是這樣時候 是最好的

3、最後,如何確定s0和sn直接的排序

 

程式碼如下:

檢視程式碼

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N=300010;

int n;
LL a[N],s[N];
bool st[N];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            s[i]=s[i-1]+a[i];
        }
        
        LL s0=s[0],sn=s[n];
        if(s0>sn)swap(s0,sn);
        sort(s,s+n+1);
        
        for(int i=0;i<=n;i++)
        {
            if(s[i]==s0)
            {
                s0=i;
                break;
            }
        }
        
        for(int i=n;i>=0;i--)
        {
            if(s[i]==sn)
            {
                sn=i;
                break;
            }
        }
        
        memset(st,0,sizeof st);
        int l=0,r=n;
        for(int i=s0;i>=0;i-=2)
        {
            a[l++]=s[i];
            st[i]=1;                
        }
        
        for(int i=sn;i<=n;i+=2)
        {
            a[r--]=s[i];
            st[i]=1;
        }
        
        for(int i=0;i<=n;i++)
        {
            if(!st[i])a[l++]=s[i];
        }
        
        LL res=0;
        
        for(int i=1;i<=n;i++)
        {
            res=max(res,abs(a[i]-a[i-1]));
        }
        
        printf("%lld\n", res);
    }
    
    
    return 0;
}

end!!!