1. 程式人生 > 實用技巧 >Codeforces Round #664 (Div. 2) D. Boboniu Chats with Du

Codeforces Round #664 (Div. 2) D. Boboniu Chats with Du

傳送門:cf1395D

題意

給定一個長度為n的陣列a[i]為當天說話的有趣值,如果a[i]>m,那麼在 i 之後有d天不能說話。否則可以每天都說話。找到一個排列使得n天有趣值總和最大,問有趣值總和的最大值是多少。

題解

很明顯用貪心。先取>m的有趣值直到取不下。根據樣例1的解釋可以看出將一個大於m的值放在最後,前邊放<m的會更優,所以此時有兩種情況,如果取了的p個大於m的值p*(d+1)(p個大於m的總共佔了多少天)大於n,那麼就要找到最後一個能說話的天后不能說話的天數,即d-(p*(d+1)-n),然後可以加上<m最大的前d-(p*(d+1)-n)天,相當於把這段放在最後說話的那天前邊。如果p*(d+1)<=n,剩下的位置就可以直接由大到小放<m的有趣值,因為最後一個>m的值後邊也有d天不能說話,所以也將最後一個>m的值移到最後,相當於再加上d個<m的值,和前邊的做法一樣。然後就可以開始用<m的段替換>m的段,如果長度為d+1的<m的剩餘的值和的最大值比所取的>m的值的最小值大,那麼就可以直接用這一段替代>m的那一段,直到沒有這樣的段可以替代位置。

說的繞繞的,當時想的就繞繞的,程式碼還行,好像是有更簡便的做法的。

程式碼

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 
 5 ll a[100100];
 6 ll b[100100];
 7 
 8 ll cmp(ll x,ll y)
 9 {
10     return x>y;
11 }
12 
13 int main()
14 {
15     ios::sync_with_stdio(false);
16     cin.tie(0);
17     cout.tie(0);
18 ll n,m,d; 19 cin>>n>>d>>m; 20 for(ll i=0;i<n;i++) cin>>a[i]; 21 sort(a,a+n,cmp); 22 ll ans=0; 23 ll k=0,p=0,q=0; 24 for(ll i=0;i<n;i++){ 25 if(a[i]<=m) b[k++]=a[i]; 26 } 27 ll cnt=0; 28 for(ll i=0;i<n-k;i++){ 29 if
(cnt>=n) break; 30 cnt++; 31 ans+=a[i]; 32 cnt+=d; 33 p++; 34 } 35 p--; 36 for(ll i=cnt;i<n;i++) ans+=b[q++]; 37 if(k==0) {cout<<ans<<endl;return 0;} 38 if(cnt>n){ 39 ll res=0; 40 ll pp=cnt-n; 41 pp=d-pp; 42 for(ll i=q;i<min(q+pp,k);i++) res+=b[i]; 43 q+=pp; 44 ans+=res; 45 } 46 else{ 47 ll res=0; 48 for(ll i=q;i<min(q+d,k);i++) res+=b[i]; 49 q+=d; 50 ans+=res; 51 } 52 while(q<k&&p>=0){ 53 ll res=0; 54 for(ll i=q;i<min(q+d+1,k);i++) res+=b[i]; 55 if(res>a[p]) ans-=a[p],ans+=res,p--; 56 else break; 57 q+=d+1; 58 } 59 cout<<ans<<endl; 60 return 0; 61 }