zoukankan      html  css  js  c++  java
  • 一类贪心题乱编

    PS:明天就要考数学了,好慌

    我们考虑一类贪心题,它们常常是某些物品带有一定价值,若干天,每次能选一定量,但是随着一段时间可决策集合越来越窄.

    对于这类题,一个比较通用的想法就是倒过来考虑,因为如果倒过来考虑,就变成决策集合单调不减,于是往往可以直接用堆之类的数据结构进行贪心.

    类似一种反悔贪心?常常体现为贪心实质是在模拟费用流(然而我基本不会网络流)

    例题1,[NOI2017]蔬菜

    题意:太长了就不说了,自己看吧,大致就是上面的模型

    发现正着做十分难做,考虑倒着贪心.

    因为第p-1天答案显然是第p天减掉最劣的决策(因为p-1对于p来说决策集合单调不减,所以p能选的所有p-1都能选,所以可以随便删)

    于是我们只要求出第P天的值,(P = max($p_{j}$)),然后就可以倒推1~P-1

    考虑倒着推怎么做.我们发现题目一堆奇奇怪怪的限制在倒推中突然就有了意义,如果某堆食物从某天开始就不变质了,就把它加进去(又是因为决策集合单调不减,对于倒着推来说,如果当前不变质,之后就不会再变质了)

    于是可以直接塞堆里,贪心

    /*[NOI2017]蔬菜*/
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int read(){
    	char c = getchar();
    	int x = 0;
    	while(c < '0' || c > '9')		c = getchar();
    	while(c >= '0' && c <= '9')		x = x * 10 + c - 48,c = getchar();
    	return x;
    }
    struct Node{
    	ll v,id;
    	Node (ll fi = 0,ll se = 0){
    		v = fi,id = se;
    	}
    	bool operator <(const Node &a)const{
    		return v < a.v;
    	} 
    };
    const int N = 1e5 + 10;
    priority_queue<Node>q;
    int a[N],s[N],c[N],x[N],n,m,k;
    int P = 1e5;
    vector<int>d[N];/*第i天会有哪些元素加进来*/
    int sel[N];
    bool vis[N];
    Node st[N];int top;
    ll ans[N];ll ss;
    #define pb push_back
    int main(){
    	n = read(),m = read(),k = read();
    	for(int i = 1; i <= n; ++i)		a[i] = read(),s[i] = read(),c[i] = read(),x[i] = read();
    	for(int i = 1; i <= n; ++i){
    		if(x[i] == 0)	d[P].pb(i);
    		else	d[min(P,(c[i] - 1 + x[i]) / x[i])].pb(i);
    	}
    	for(int i = P; i; --i){
    		for(int j = 0; j < (int)d[i].size(); ++j){
    			int x = d[i][j];
    			q.push(Node(a[x] + s[x],d[i][j]));
    		}
    		for(int j = m; j && !q.empty();){
    			Node now = q.top();q.pop();
    			if(!vis[now.id]){
    				sel[now.id]++;
    				ans[P] += now.v;
    				if(c[now.id] > 1)	q.push(Node(a[now.id],now.id));
    				vis[now.id] = 1;
    				--j;
    			}
    			else{
    				int res = min(1ll * j,c[now.id] - 1ll * (i - 1) * x[now.id] - sel[now.id]);
    				j -= res;ans[P] += 1ll * res * now.v;
    				sel[now.id] += res;if(sel[now.id] != c[now.id])		st[++top] = now;
    			}
    		}
    		while(top)	q.push(st[top]),top--;
    	}
    	while(q.size())		q.pop();
    	memset(vis,0,sizeof(vis));
    	for(int i = 1; i <= n; ++i){
    		ss += sel[i];
    		if(sel[i] == 0)	continue;
    		if(sel[i] == 1)		q.push(Node(-a[i]-s[i],i));
    		else	q.push(Node(-a[i],i));
    	}
    	for(int i = P - 1; i; --i){
    		ans[i] = ans[i+1];
    		while(ss > i * m){
    			ss--;
    			Node now = q.top();q.pop();
    			ans[i] -= -now.v;sel[now.id]--;
    			if(sel[now.id] > 1)		q.push(now);
    			if(sel[now.id] == 1)	q.push(Node(-a[now.id] - s[now.id],now.id));
    		}
    	}
    //	return 0;
    	while(k--){
    		int p = read();
    		printf("%lld
    ",ans[p]);
    	} 
    	return 0;
    }
    

      upd:还有从费用流角度的理解,先咕着

    例题2.[CF505E]

    首先肯定是要二分的,设当前二分的值为H,所以就变成了最大值能否不超过H

    有一个极度鬼畜的max($h_{i}$ - p,0)

    我们依然考虑倒着做,考虑设所有值初始位置都是H,每时刻-=a[i],任意时刻都不能<0,你可以给它加上p,是否存在一种方案,使得最终位置 >=  h[i]

    只要按变成<0的顺序,优先+那些会先<0的,贪心地+p最后再检查是否全部合法就可以了.

    /*CF505E Mr. Kitayuta vs. Bamboos*/
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int read(){
    	char c = getchar();
    	int x = 0;
    	while(c < '0' || c > '9')		c = getchar();
    	while(c >= '0' && c <= '9')		x = x * 10 + c - 48,c = getchar();
    	return x;
    }
    const int N = 1e5 + 10;
    ll a[N],h[N],n,m,k,p;
    struct NUM{
    	int ed;ll v;int id,st;/*几天后会小于0*/
    	bool operator <(const NUM &a)const{
    		return ed > a.ed;
    	}
    	NUM (int _a = 0,ll _b = 0,int _c = 0,int _d = 0){
    		ed = _a,v = _b,id = _c,st = _d;
    	}
    };
    priority_queue<NUM>q;
    bool check(ll x){
    	while(q.size())		q.pop();
    	for(int i = 1; i <= n; ++i){
    		if(x - m * a[i] >= h[i])	continue;
    		q.push(NUM(x / a[i],x,i,0));
    //		cout<<i<<' '<<x / a[i]<<endl;
    	}
    	for(int i = 1; i <= m; ++i){
    		ll res = m - i;
    		for(int j = 1; j <= k; ++j){
    			if(q.empty())	return 1;
    			NUM now = q.top();q.pop();
    			if(now.ed < i)	return 0;
    			ll v = now.v - 1ll * (i - now.st) * a[now.id] + p;
    			if(v - res * a[now.id] >= h[now.id])		continue;
    			q.push(NUM(max((ll)i,i + v / a[now.id]),v,now.id,i));
    		}
    	}
    	if(q.empty())	return 1;return 0;
    }
    int main(){
    	n = read(),m = read(),k = read(),p = read();
    	for(int i = 1; i <= n; ++i)		h[i] = read(),a[i] = read();
    	ll l = 1,r = 1e15;
    	ll ans = 0;
    	while(l <= r){
    		ll mid = (l + r) >> 1;
    		if(check(mid)){
    			ans = mid;
    			r = mid - 1;
    		}
    		else	l = mid + 1;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

      

  • 相关阅读:
    CSS3的常用属性(一)
    Shiro授权认证原理和流程
    mysql存储引擎
    mysql索引的注意事项
    CSS的常用属性(三)
    CSS的常用属性(二)
    CSS的常用属性(一)
    常用文档站点
    Spring和SpringMVC父子容器关系初窥
    内部类学习资料分享
  • 原文地址:https://www.cnblogs.com/y-dove/p/14337550.html
Copyright © 2011-2022 走看看