[Acwing藍橋杯貪心] 1248. 靈能傳輸
阿新 • • 發佈:2022-03-30
大概題意:給一個長度為數列,除了兩個端點以外,任意選一個點,可以將該點的值分給相鄰的兩個點,也可以得到相鄰的兩個點的值
整個數列的總能量不變 就是能量輸出給相鄰的點或者從相鄰的點輸入。
分析:
這是一個貪心題,時間複雜度 倒不是問題 關鍵點是思路
這個題有三個難點,不太好想的地方:
設 每個點的元素 都存在 陣列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!!!