Codeforces 815 (div2)D1 && 820 (div3)D 题解

Codeforces 815 (div2)D1 && 820 (div3)D 题解

题目链接

题目大意是让求一个数组b的最大长度,数组b为数组a的下标(从0开始),其中对任意的 b i b_i bi要满足:
a b i a_{b_i} abi^ b i + 1 b_{i+1} bi+1 < a b i + 1 a_{b_{i+1}} abi+1^ b i b_i bi
很明显的dp问题,但是数据范围较大,直接暴力时间复杂度为 n 2 n^2 n2,稳稳超时。那考虑下b序列有什么性质。我们可以发现 a i a_i ai的范围很小,最大为200,因此其异或上一个值后最大值不会超过256,所以可以得出状态转移的范围不会超过256,因此我们可以不用循环很多就能得出最终解。
**定义 f i f_i fi为选 a i a_i ai时, b i b_i bi的最长长度,那么转移方程就很明显了:
f i f_i fi=max( f i f_i fi , f j f_j fj) ( a j a_j aj^ i i i < a i a_i ai^ j j j)
时间复杂度为O(n*400), 可以通过此题。
code:

#include<bits/stdc++.h>

using namespace std;

//#define int long long
const int N=4e5+10;
int a[N],f[N]; 

void work()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i]; f[i]=1;
	}
	
	for(int i=0;i<n;i++){
		for(int j=max(0,i-400);j<i;j++){
			if((a[j]^i)<(a[i]^j)) f[i]=max(f[i],f[j]+1);
		}
	}
	
	cout<<*max_element(f,f+n)<<endl;
}
signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		work();
	}
	return 0;
} 

题目链接

题目大意:有n个人出去吃饭,第 i i i个人想花 a i a_i ai的钱,但他实际有 b i b_i bi的钱。
求最多能把这些人分成几组,每组最少两人,使得组内的 a i a_i ai总和<= b i b_i bi总和

思路:很明显的贪心问题,我们另 c i c_i ci a i a_i ai- b i b_i bi, 则可以转变为从 c i c_i ci分组,使得组内和>=0 . **可以知道,任意两个>=0的 c i c_i ci, 我们都可以分成一组,若对于所有 c i c_i ci都大于0,则答案为n/2, 显然这样是最优的答案。关键是对负数怎么操作,那我们贪心的让组内最大值与最小值结合,若其相加>=0,则贪心的取这一对,若<0,则直接舍弃最小值,换为次小值继续结合。为什么是最优的呢? 因为一正一负结合,相当于看作省去了一个正数,而两正一负结合,不如直接两个正数结合, 因此我们排好序后,双指针模拟结合过程即可。
时间复杂度为O(n*logn)。
code:

#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> pii;
#define x first
#define y second
const int N=2e5+10;
int a[N];
void work()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		a[i]=x-a[i];
	}
	sort(a+1,a+1+n);
	
	int ans=0;
	for(int i=1,j=n;i<j;){
		if(a[i]+a[j]>=0) {
			ans++; i++,j--;
		}
		else i++;
	}
	
	cout<<ans<<endl;
}
signed main()
{
	int t;
	cin>>t;
	while(t--)
	{
		work();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值