CS R19 C(套路,二分or two pointer). D(构造,相邻位不同,字典最小),E(???)

本文针对几道算法竞赛题目提供了解决方案,包括通过暴力确定部分配对状态来解决组合问题,以及采用二分查找和动态规划策略求解最大价值路径问题。此外,还介绍了一种构造最小字典序序列的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem B:
套路:暴力确定前两个(或者一个)配对状态 则剩余状态也能确定. 这种类型前期感觉经常出.

Problem C:

题意:一条直线先有n个点 每个点在位置x[i],价值为a[i],初始在s点 最多走K单位距离.
n<=1e5,问最多能得到的价钱.
从s起 刚开始向左 或者 向右  然后最多改变一次方向(一直改变方向不是很迷...)

然后枚举刚开拿了左边多少个点,二分最远还能到右边哪一个点.对于初始右边也是如此.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
ll n,s,K,pre[N],pos;
struct node{
	ll x,w;
}a[N];
bool cmp(node a,node b)
{
	return a.x<b.x;
}
ll work(int k,int cur)
{
	int l=pos+1,r=n;
	ll res=pos;
	while(l<=r)
	{
		int m=l+r>>1;
		if(a[m].x-a[cur].x<=k)
			res=m,l=m+1;
		else
			r=m-1;
	}
//	cout<<cur<<' '<<k<<' '<<res<<' '<<pos<<' ';
	return pre[res]-pre[pos];
}
ll Work(int k,int cur)
{
	int l=1,r=pos;
	ll res=pos;
	while(l<=r)
	{
		int m=l+r>>1;
		if(a[cur].x-a[m].x<=k)
			res=m,r=m-1;
		else
			l=m+1;
	}
	return pre[pos]-pre[res-1];
}
int main()
{
	cin>>n>>s>>K;
	for(int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i].x,&a[i].w);
	sort(a+1,a+1+n,cmp);
	
	pos=n;
	for(int i=1;i<=n;i++)
		if(a[i].x>s)
		{
			pos=i;
			break;
		}
	for(int i=n;i>=pos;i--)
		a[i+1]=a[i];
	a[pos].x=s,a[pos].w=0,n++;
	
	for(int i=1;i<=n;i++)
		pre[i]=pre[i-1]+a[i].w;
	
	
	ll ans=0;
	for(int i=1;i<=pos;i++)
	{
		ll ned=abs(a[i].x-a[pos].x),val=0;
		ll k=K;
		if(k>=ned)
		{
			k-=ned;
			val+=pre[pos]-pre[i-1];		
			val+=work(k,i);
			ans=max(ans,val);
		//	cout<<ans<<endl;
		}
		else
			break;
	}
	for(int i=pos;i<=n;i++)
	{
		ll ned=abs(a[i].x-a[pos].x),val=0;
		ll k=K;
		if(k>=ned)
		{
			k-=ned;
			val+=pre[i]-pre[pos];		
			val+=Work(k,i);
			ans=max(ans,val);
		}
		else
			break;
	}
	cout<<ans<<endl;
	return 0;
}
Problem D
题意:给出n个数的序列a,可以任意改变序列a元素的位置 要求最终序列相邻元素不能相同
n,a[i]<=1e5,输出满足条件的序列中 字典序最小的哪一个.


n个数的序列相邻要不同 则频率最高为n/2(上取整),否则无解.
构造:加入已经放了前i个数, 第i+1个数应该放哪一个?
若当前频率最高*2 > n-i 则第i+1个数 只能放频率最高的.
否则 第i+1个数没有限制,放当前最小的并且和前面不同即可.然后用set维护一下.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
multiset<int> a;
set<ii> s;
int n,x,cnt[N];
int getmx()
{
	return s.rbegin()->second;
}
void use(int x)
{
	s.erase(ii(cnt[x],x));
	--cnt[x];
	s.insert(ii(cnt[x],x));
	
	a.erase(a.find(x));
}
int main()
{
	int mx=0;
	cin>>n;
	for(int i=0;i<n;i++)
		scanf("%d",&x),cnt[x]++,mx=max(mx,x),a.insert(x);
	for(int i=1;i<=mx;i++)
	{
		if(cnt[i])
			s.insert(ii(cnt[i],i));
		if(cnt[i]>(n+1)/2)
		{
			puts("-1");
			return 0;
		}
	}
	int pr=-1;
	for(int i=0;i<n;i++)
	{
		if(cnt[getmx()]*2>n-i)
		{
			int k=getmx();
			cout<<k<<' ';
			use(k),pr=k;
		}
		else
		{
			int k=*a.begin();
			if(k==pr)
				k=*a.upper_bound(k);
			cout<<k<<' ';
			use(k),pr=k;
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值