Bzoj 2288 生日禮物題解
阿新 • • 發佈:2017-09-22
連接 意思 sca while str all -- printf 備份
Submit: 856 Solved: 260
[Submit][Status][Discuss]
), 序列的長度和可以選擇的部分。
5 2
2 -3 2 -1 2
2288: 【POJ Challenge】生日禮物
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 856 Solved: 260
[Submit][Status][Discuss]
Description
ftiasch 18歲生日的時候,lqp18_31給她看了一個神奇的序列 A1, A2, ..., AN. 她被允許選擇不超過 M 個連續的部分作為自己的生日禮物。
自然地,ftiasch想要知道選擇元素之和的最大值。你能幫助她嗎?
Input
第1行,兩個整數 N (1 ≤ N ≤ 105) 和 M (0 ≤ M ≤ 105
第2行, N 個整數 A1, A2, ..., AN (0 ≤ |Ai| ≤ 104), 序列。
Output
一個整數,最大的和。
Sample Input
5 2
2 -3 2 -1 2
Sample Output
5HINT
Source
這道題當時第一眼以為連續的m個數,然後以為是二分加上單調隊列,還好又讀了一遍,發現是m個區間,這就比較有意思了,首先,我們可以先把所有符號相同的區間合在一起,來簡化一下問題,然後這道題就變成了在一個正數與負數相間的數列中找出m個數使他們的和最大,但是我們要註意一點,這些數其實還可以合並成一個數,所以我們不能拿貪心去做。所以我們可以把答案分為兩種情況,第一,所有正數的個數小於等於m那麽我們可以直接輸出了,第二正數的個數大於m,那麽我們就有又有兩種選擇了,舍去某個正數或通過一個負數將兩個區間合並在一起。對於位於首尾兩個位置的負數我們可以的知他們並無法連接兩個正數,換言之,選他們並不能減少當前所選的區間,所以我們在一開始就應當把他們刨去。同時我們也可以發現如果我們選了一個負數那麽兩側的正數是不能再被選擇丟掉的,而整個序列又是正負相間的,所以我們就可以將這個問題轉化為在當前數列中選取若幹個不相鄰的數數是他們的和最小。然後,這道題就是Bzoj1150數據備份了。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<vector> 10 #define N 100005 11 using namespace std; 12 int n,m,a[N],zz;View Code13 struct no 14 { 15 long long sum; 16 int mid; 17 bool friend operator > (no a,no b) 18 { 19 return a.sum>b.sum; 20 } 21 }node[N]; 22 int pre[N],fro[N]; 23 bool fw[N]; 24 priority_queue<no,vector<no>,greater<no > > q1; 25 int main() 26 { 27 scanf("%d%d",&n,&m); 28 for(int i=1;i<=n;i++) 29 scanf("%d",&a[i]); 30 long long sm=0,ans=0,js=0,la=0; 31 for(int i=1;i<=n;i++) 32 { 33 if(a[i]==0)continue; 34 if(a[i]*la<0) 35 { 36 zz++; 37 node[zz].sum=sm; 38 if(sm>0) 39 { 40 js++; 41 ans+=sm; 42 } 43 sm=0; 44 if(zz==1&&la<0)zz=0; 45 } 46 la=a[i]; 47 sm+=a[i]; 48 } 49 if(sm>0) 50 { 51 js++,ans+=sm; 52 zz++; 53 node[zz].sum=sm; 54 } 55 if(js<=m) 56 { 57 printf("%lld\n",ans); 58 exit(0); 59 } 60 m=js-m; 61 for(int i=1;i<=zz;i++) 62 { 63 node[i].mid=i; 64 node[i].sum=abs(node[i].sum); 65 q1.push(node[i]); 66 pre[i]=i-1,fro[i]=i+1; 67 } 68 fro[zz]=0; 69 node[0].sum=0x7fffffff; 70 while(m--) 71 { 72 while(fw[q1.top().mid]) q1.pop(); 73 no tt=q1.top();q1.pop(); 74 int x=tt.mid; 75 ans-=tt.sum; 76 tt.sum=-tt.sum; 77 tt.sum+=node[pre[x]].sum+node[fro[x]].sum; 78 node[x].sum=tt.sum; 79 80 fw[pre[x]]=fw[fro[x]]=1; 81 pre[x]=pre[pre[x]]; 82 fro[x]=fro[fro[x]]; 83 pre[fro[x]]=x; 84 fro[pre[x]]=x; 85 q1.push(tt); 86 } 87 printf("%lld\n",ans); 88 return 0; 89 }
Bzoj 2288 生日禮物題解