题解 Merchant

传送门

可以发现如果我们最终选择的物品集合已经确定,就很好求了
\(\sum k*t+\sum b \geqslant s\) ,二分即可
但现在我们无法确定该选哪些物品

因此我们只需要check一下0时刻是否符合条件,如果不符合则进行二分。
注意check的时候我们只需要找出最大的 \(m\) 个即可

有点玄学。
证一下它有单调性:
因为保证有解,令存在一个解为时刻 \(t\)
那么此时存在一个 \(\sum k*t+\sum b \geqslant s\)
考虑时刻 \(t+1\),发现多了个 \(\sum k\)
若 \(\sum k > 0\) ,可以二分
若 \(\sum k \leqslant 0\) ,0时刻一定更优,不必二分

  • 有空复习下nth_element的使用

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long 
#define reg register int 
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m; ll s;
ll k[N], b[N];
const double eps=1e-8;

namespace force{
	ll ans=(ll)(1e18);
	void solve() {
		int lim=1<<n;
		double k1, b1, s1=s, t;
		for (reg s=1,s2,cnt; s<lim; ++s) {
			k1=0; b1=0; cnt=0; s2=s;
			do {s2&=(s2-1); ++cnt;} while (s2);
			if (cnt>m) continue;
			for (reg i=0; i<n; ++i) if (s&(1<<i))
				k1+=k[i+1], b1+=b[i+1];
			t=(s1-b1)/k1;
			//cout<<"t: "<<t<<' '<<bitset<5>(s)<<endl;
			if (ceil(t)>=-eps && k1*ceil(t)+b1>=s1-eps) ans=min(ans, (ll)ceil(t));
			if (floor(t)>=-eps && k1*floor(t)+b1>=s1-eps) ans=min(ans, (ll)floor(t));
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task1{
	ll tem[N];
	inline bool cmp(ll a, ll b) {return a>b;}
	bool check(ll t) {
		for (reg i=1; i<=n; ++i) tem[i]=k[i]*t+b[i];
		sort(tem+1, tem+n+1, cmp);
		ll sum=0;
		for (reg i=1; i<=m; ++i) 
			if ((sum+=tem[i])>=s) return 1;
		return 0;
	}
	void solve() {
		ll l=0, r=(ll)(1e9), mid;
		while (l<=r) {
			mid=(l+r)>>1;
			if (!check(mid)) l=mid+1;
			else r=mid-1;
		}
		printf("%lld\n", l);
		exit(0);
	}
}

namespace task{
	ll tem[N];
	inline bool cmp(ll a, ll b) {return a>b;}
	bool check(ll t) {
		//cout<<"check "<<t<<endl;
		for (reg i=1; i<=n; ++i) tem[i]=k[i]*t+b[i];
		nth_element(tem+1, tem+m, tem+n+1, cmp);
		//cout<<"tem: "; for (int i=1; i<=n; ++i) cout<<tem[i]<<' '; cout<<endl;
		ll sum=0;
		for (reg i=1; i<=m; ++i) if (tem[i]>0 && (sum+=tem[i])>=s) return 1;
		return 0;
	}
	void solve() {
		for (int i=1; i<=n; ++i) tem[i]=b[i];
		sort(tem+1, tem+n+1, cmp);
		ll sum=0;
		for (reg i=1; i<=m; ++i) if ((sum+=tem[i])>=s) {puts("0"); exit(0);}
		ll l=0, r=(ll)(1e9), mid;
		while (l<=r) {
			mid=(l+r)>>1;
			if (!check(mid)) l=mid+1;
			else r=mid-1;
		}
		printf("%lld\n", l);
		exit(0);
	}
}

signed main()
{
	bool geq=1, leq=1;
	n=read(); m=read(); s=read();
	for (int i=1; i<=n; ++i) {
		k[i]=read(); b[i]=read();
		if (b[i]>=s) {puts("0"); return 0;}
		if (k[i]>0) leq=0;
		else if (k[i]<0) geq=0;
	}
	//if (n<=20) force::solve();
	//else if (geq) task1::solve();
	//else if (leq) {puts("0"); return 0;}
	task::solve();
	
	return 0;
}
上一篇:Linux简单的运行脚本


下一篇:浏览器下载文件到本地