当前位置:   article > 正文

codeforces刷题_如何刷codeforces

如何刷codeforces

https://codeforces.com/contest/1610/problem/C
题意:有n个人,富裕程度1~n, 要举行派对,要求对于每个人,来的人中比他富的不超过 a i a_i ai, 比他穷的不超过 b i b_i bi,问最多能邀请多少人来.

思路:二分答案,把答案最大化。关键是怎么统计能邀请多少人,假设可以邀请mid人,对于每个人,记录当前已经邀请了cnt人,如果 b i b_i bi>=cnt,并且 a i a_i ai>=mid-cnt-1, 那么说明可以邀请这个人。
code :

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

//head
const int N=2e5+10;
int a[N],b[N];
int n;

bool check(int mid)//mid为答案选几个
{
	int cnt=0;//当前选了cnt个
	for(int i=1;i<=n;i++){
		if(b[i]>=cnt&&a[i]>=mid-cnt-1) cnt++;
		
	}
	if(cnt>=mid) return 1;
	return 0;
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
	}
	int l=1,r=n;
	while(l<r)
	{
		int mid=l+r+1>>1;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout<<r<<endl;
}
signed main()
{
	ios;
	int t;
	cin>>t;
	//t=1;
	while(t--)
	{
		solve();
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

添加链接描述

题目大意:给定一个序列 a ,a为未知序列,长度为n,给m个已知信息,为从 a l a_l al a r a_r ar 的或的值为x, a的所有子集中元素异或值的和。

思路:对二进制下每一位分析,就比如对于每个元素的第3位,构成一个集合b,b={b1,b2,b3,…bn}, 对于某个 b i b_i bi, 若 b i b_i bi 为1,则将集合分为含有 b i b_i bi和不含 b i b_i bi的两种集合,其数量均为 2 n − 1 2^{n-1} 2n1个,其异或值为1的一定在这两个集合的其中一个,因此每一位1的贡献为 :当前1对应的值 * 2 n − 1 2^{n-1} 2n1, 那么怎么判断当前位是否有1呢?直接将所有x或起来即可。

code:

#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
//head
typedef pair<int,int> pii;
const int N=2e5+10,mod=1e9+7;

int qmi(int a,int k)
{
	int ans=1;
	while(k)
	{
		if(k&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		k>>=1;
	}
	return ans;
}
void solve()
{
	int n,m;
	cin>>n>>m;
	int ans=0;
	while(m--)
	{
		int l,r,x;
		cin>>l>>r>>x;
		ans|=x;
	}
	cout<<ans*qmi(2,n-1)%mod<<endl;
}
signed main()
{
	ios;
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

添加链接描述

题目大意 : 将长度为n的序列a,(初始全为1),最多经过k次变化,能获得的最大值是多少。每次变化操作为: a i a_i ai+= a i a_i ai/x;将 a i a_i ai 变为 b i b_i bi 可以获得 c i c_i ci 的值。

思路:01背包求解,预处理出来每个 a i a_i ai 变为 b i b_i bi 的最小次数, 以该次数为体积,以 c i c_i ci 为价值做一遍01背包即可。需要注意的是每个数最大变化次数不超过12次,而k值较大,因此在求体积时要与k取 min。

code:


#include<bits/stdc++.h>

using namespace std;
#define endl '\n'
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

//head
const int N=1e5+10;
int b[N],w[N],v[N];
int n,k;
int f[N],cnt[100010];

void solve()
{
	memset(f,0,sizeof f);
	cin>>n>>k;
	int sum=0;
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=n;i++) cin>>w[i];
	for(int i=1;i<=n;i++) {
		v[i]=cnt[b[i]];
		sum+=v[i];
	}
	k=min(k,sum);
	for(int i=1;i<=n;i++){
		for(int j=k;j>=v[i];j--){
			f[j]=max(f[j-v[i]]+w[i],f[j]);
		}
	}
	cout<<f[k]<<endl;
}
signed main()
{

	memset(cnt,0x3f,sizeof cnt);
	cnt[1]=0;
	for(int i=1;i<=1e3;i++){
		for(int j=1;j<=i;j++){
			cnt[i+(i/j)]=min(cnt[i+(i/j)],cnt[i]+1);
		}
	}

	//ios;
	int t;
	cin>>t;
	//t=1;
	
	while(t--)
	{
		solve();
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/72590
推荐阅读
相关标签
  

闽ICP备14008679号