1. 程式人生 > 實用技巧 >牛客每日一題 tokitsukaze and Soldier 貪心 + dp思維

牛客每日一題 tokitsukaze and Soldier 貪心 + dp思維

(這題好像並不需要優先佇列

題意描述

看題解的時候看歪了
寫成了從小到大列舉,好像發現不需要優先佇列只需要排個序就可以了

題解:
列舉士兵限制為1-n的時候的最大值
可以想象的是士兵限制為k時,最大值是所有s大於等於k的前k(或只有不超過k個士兵滿足)大的士兵的v之和
暴力做的時間是不可取的
那麼可以先將士兵按v從大到小排序
列舉k時,選擇最大的並且s大於等於k的前k個v之和,每次暴力不可取。
那麼考慮k與k-1的關係(類似dp


summ[k-1]指的是在dp[k-1]中s等於k-1的所有士兵之和
newsum[k]指的是在從k-1列舉的前k-1個最大值的末尾開始選擇的新的前k大
(不會用LaTeX只能用解釋了orz)
感覺越寫越亂了,看程式碼!

程式碼:

/*
link: https://ac.nowcoder.com/acm/problem/50439
tags: greedy
*/
#include<bits/stdc++.h>
#define to_l(a) ((a)<<1)
#define to_r(a) ((a)<<1|1)
#define lowbit(a) ((a)&(-a))
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
const int int_inf=0x3f3f3f3f;
const ll ll_inf=0x3f3f3f3f3f3f3f3f;
const int max_n=1e5+5;
struct node{
	int v,s;
	bool operator < (const node & a) const {
		return s>a.s;
	}
};
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int i,j;
	int n;
	cin>>n;
	vector<node> a(n);
	vector<ll> summ(n+1); 
	vector<int> cnt(n+1);
	for(i=0;i<n;i++){
		cin>>a[i].v>>a[i].s;
	}
	int size=0;
	ll sum=0,ans=-1;//sum就是每一輪的dp值
	sort(a.begin(),a.end(),[](const node a,const node b) -> bool {
		return a.v>b.v;
	});
	for(j=0,i=1;i<=n;i++){
		sum-=summ[i-1];
		size-=cnt[i-1];
		while(j<n){
			if(a[j].s>=i){
				summ[a[j].s]+=a[j].v;
				size++;
				cnt[a[j].s]++;
				sum+=a[j].v;
			}
			j++;
			if(size==i) break;
		}
		ans=max(ans,sum);
	}
	cout<<ans<<endl;
	return 0;
}