Codeforces Round 960 (Div. 2)

A.模拟:https://codeforces.com/contest/1995/problem/A

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,t,k;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>k;
		int cnt=0;
		if(k==0) cout<<0<<endl;
		else if(k<=n) cout<<1<<endl;
		else{
			cnt++;
			k-=n;
			for(int i=n-1;i>=1;i--){
				if(k<=0) break;
				else if(k<=i){
					cnt++;
					k-=i;
				}
				else{
					cnt+=2;
					k-=2*i;
				}
			}
			cout<<cnt<<endl;
		}
	}
}

B枚举:https://codeforces.com/contest/1995/problem/B1

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,t,m;
ll a[200010];
struct node{
	ll x,ci;
}b[200010];
int cnt=1;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>m;
		for(int i=1;i<=n;i++) cin>>a[i];
		sort(a+1,a+n+1);
		ll ans=0;
		//枚举两个
		cnt=1;
		int j=1;
		for(int i=1;i<=n;i++){
			if(a[i]==a[j]) continue;
			b[cnt++]={a[j],i-j};
			j=i;
		} 
		b[cnt++]={a[j],n-j+1};
		for(int i=1;i<cnt-1;i++){
			ll x=b[i].x,k1=b[i].ci,y=b[i+1].x,k2=b[i+1].ci;
			if(x>m) break;
			if(y!=x+1) continue;
			for(int j=0;j<=k1;j++){
				ll fk=m-j*x;
				if(fk==0) ans=m;
				else if(fk<0) break;
				else{
					ll cc=fk/y;
					if(cc<=k2) ans=max(ans,j*x+cc*y);
					else ans=max(ans,j*x+k2*y);
				}
			}
		}
		for(int i=1;i<cnt;i++){
			ll x=b[i].x,k1=b[i].ci;
			if(x>m) break;
			ll cc=m/x;
			if(cc<=k1) ans=max(ans,cc*x);
			else ans=max(ans,x*k1);
		}
		cout<<ans<<endl;
	}
}

C数学,分类讨论:https://codeforces.com/contest/1995/problem/B2

把x,x+1当成同等地位可能反而会把问题复杂化,我们不妨以x为主,x+1作为x的补充:

首先,问题就是给你两个数:x,x+1以及他们的个数k1,k2,如何凑出<=m的最大值。

假如不考虑x+1的存在,答案就显然是min(m/x,k1)*x

考虑x+1带来的影响:一方面假如k1\geqslant m/x,那么对于m/x*x来说就是使他的解变成了一个区间:[m/x*x,m/x*x+k2].

另一方面假如k1< m/x,那么就让k2去填充(m-k1*x)/(x+1),剩下的就对用了的k1个进行优化,也就是:[k1*x+(x+1)*min(k2,(m-k1*x)/(x+1)),k1*x+(x+1)*min(k2,(m-k1*x)/(x+1))+min(k1,k2-min(k2,(m-k1*x)/(x+1)))]

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define x first
#define y second
ll t,n,m;
pair<ll,ll> a[200010];
ll ans=0;
int main(){
	cin>>t;
	while(t--){
		ans=0;
		cin>>n>>m;
		for(int i=1;i<=n;i++) cin>>a[i].first;
		for(int i=1;i<=n;i++) cin>>a[i].second;
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++){
			ans=max(ans,min(m/a[i].x,a[i].y)*a[i].x);
		}
		//枚举两个 
		for(int i=1;i<=n-1;i++){
			if(a[i].x!=a[i+1].x-1) continue;
			ll cnt1=m/a[i].x;
			if(cnt1<=a[i].y){
                if(cnt1!=0) ans=max(ans,min(cnt1*a[i].x+min(a[i+1].y,cnt1),m));
				
			}
			else{//需要用a[i+1]继续填充
				 ll cnt2=(m-a[i].x*a[i].y)/a[i+1].x;
				 if(cnt2<=a[i+1].y){
                    //if(cnt2==0) ans=max(ans,a[i])
				 	ans=max(ans,min(m,a[i].x*a[i].y+a[i+1].x*cnt2+min(a[i+1].y-cnt2,a[i].y)));
				 }
				 else{
				 	ans=max(ans,a[i].x*a[i].y+a[i+1].x*a[i+1].y);
				 }
			}
		}
	cout<<ans<<endl;
	}
}

D。数学:https://codeforces.com/contest/1995/problem/C

假如后面的数比前面的小就平方,一旦比他大就下一个,这个贪心是显然的,但是问题在如果真的老实平方化后面的数会非常大难以表示,于是我们进一步思考:

设前面的数是a,他要被平方k次,现在我们求他后面的b要平方几次:

{​{a}^{2^{k}}}\leqslant {​{b}^{2^{k1}}}

通过不停的开方可以得到:{​{a}^{2^{0}}}\leqslant {​{b}^{2^{k1-k}}}

于是我们可以记录a的平方次数,然后枚举k1-k(在5的时候b就以经比a的数据范围大了)即可。

当然k1-k存在负数,我们把指数放到a头上对称来一次即可,具体见下面AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,a[200010];
ll b[200010];
ll pow1(ll a,ll b){
	ll res=0;
	while(b){
		if(b&1) res+=a;
		b>>=1;
		a=a*a;
	}
	return res;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		ll cnt=0;
		for(int i=2;i<=n;i++){
			if(a[i-1]!=1&&a[i]==1){
				cnt=-1;
				break;
			}
			for(int k=0;k<=5;k++){
				ll fk=2;
				ll mi=pow(fk,k);
				if(pow(a[i],mi)>=a[i-1]&&k!=0){
					b[i]=b[i-1]+k;
					cnt+=b[i];
					break;
				}
				else if(pow(a[i],mi)>=a[i-1]&&k==0){
					for(int j=5;j>=0;j--){
						ll ck=pow(fk,j);
						if(pow(a[i-1],ck)<=a[i]){
							ll kk=0;
							b[i]=max(b[i-1]-j,kk);
							cnt+=b[i];
							break;
						}
					}
					break;
				}
			}
		}
		cout<<cnt<<endl;
	}
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值