noip多校26

考试过程:这次考试难度较大,读完四个题之后发现只有T1可做,于是就死磕T1。我列出来一个一元二次方程,证明了这是一个单峰函数,然后因为直接取最小值不对,我就打了一个三分套二分,结果可能是精度问题挂了。剩下的几道题基本上连暴力分都没有,属实离谱。

T1 NOIP2018

思路:二分一个 mid,表示我们把代价 ≤mid 的货币全部兑换,可以 O(1)计算出这样的选择的代价,如果 > x 则这个值不可取,如果合法,也可以O(1) 计算出兑换出的货币数量。注意边界情况就是最后可能会剩下一些钱,然而这些钱可能能够再买一个最便宜的那个,特判一下就好了。记得开\(int128\),这东西还是比较好用的。
时间复杂度 O(n log x)。
代码如下:

AC_code

#include<bits/stdc++.h>
#define int __int128
#define ii inline int
#define iv inline void
#define D double
using namespace std;
const int N=1e5+10;
const double eps=1e-8;
int q,a,b,c,d,x,u1,u2;
ii read()
{
	int x=0; char ch=getchar(); bool f=1;
	while(ch<'0' or ch>'9')
	{
		if(ch=='-') f=0;
		ch=getchar();
	}
	while(ch>='0' and ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return f?x:(-x);
}
int check(int v,int flag)
{
	int num1=(v>=a)?((v-a+b)/b):0;
	int num2=(v>=c)?((v-c+d)/d):0;
	int sum=(a*num1+((num1*(num1-1))/2)*b) + (num2*c+((num2*(num2-1))/2)*d);
	if(flag) u1=num1+num2,a+=num1*b,c+=num2*d;
	return sum;
}
signed main()
{
	freopen("money.in","r",stdin);
	freopen("money.out","w",stdout);
	q=read();
	while(q--)
	{
		a=read(),b=read(),c=read(),d=read(),x=read();
		if(x<a and x<c) {printf("0\n");continue;}
		int l=0,r=x,ans=0;
		u1=0,u2=0;
		int P=0;
		while(l<=r)
		{
			int mid=(l+r)/2;
			P=check(mid,0);
			if(P<=x) ans=mid,l=mid+1;
			else r=mid-1;
		}
		x-=check(ans,1);
		ans=u1;
		if(min(a,c)<=x) ans++;
		printf("%lld\n",(long long)ans);
	}
	return 0;
}
/*
*/


posted @ 2021-11-09 06:15  WindZR  阅读(26)  评论(0编辑  收藏  举报