Codeforces Round #767 (Div. 2) 补题题解(前四题 rating<=2000)


比赛效果还行,过了两道题,继续加油

比赛传送门
官方题解


A Square Counting

简单思维
原题传送门

#include<bits/stdc++.h>

using namespace std;

#define int long long
#define pb push_back
#define rep(i, a, b) for(int i = a; i <= b; ++ i)

const int N = 1e5 + 10;

int n, s;
int T;

signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
//	
	scanf("%lld", &T);
	while(T -- ){
		scanf("%lld%lld", &n, &s);
		int y = s / (n * n);
		cout<<y<<endl;
	}
	
	return 0;
}

B Quality vs Quantity

原题传送门
简单思维

#include<bits/stdc++.h>

using namespace std;

#define int long long
#define pb push_back
#define rep(i, a, b) for(int i = a; i <= b; ++ i)

const int N = 2e5 + 10;

int n;
int T;
int a[N];
int s[N];

signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
//	
	scanf("%lld", &T);
	while(T -- ){
		scanf("%lld", &n);
		
		rep(i, 1, n){
			scanf("%lld", &a[i]);
		}
		
		sort(a + 1, a + n + 1);
		
		rep(i, 1, n){
			s[i] = s[i - 1] + a[i];
		}
		
		if(n % 2 == 0){
			if((s[n] - s[(n / 2) + 1]) - s[n / 2] > 0){
				printf("YES\n");
			}
			else{
				printf("NO\n");
			}
		}
		else{
			if((s[n] - s[(n / 2) + 1]) - s[(n / 2) + 1] > 0){
				printf("YES\n");
			}
			else{
				printf("NO\n");
			}
		}
	}
	
	return 0;
}

C Factorials and Powers of Two

原题传送门
算法流程:
先计算出所有小于1e12的阶乘数,将这些阶乘放入一个数组
利用二进制进行随机组合,将所有阶乘的组合形式都出现,让m减去这些组合形式的和
只有当m减去这些组合的和大于等于0时,m才有可能是被这些阶乘数构成的,此时s的1的个数存的就是阶乘的个数
所以此时得出二进制m剩余的1的个数和s中1的个数及此时的k值,循环所有阶乘数的组合,得出ans的最小值

#include<bits/stdc++.h>

using namespace std;

const long long N = 1e12 + 10;

#define int long long 

 
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int t;
	cin>>t;
	while(t -- ){
		int n;
		cin>>n;
		int fe[15];
		fe[0] = 1;
		for(int i = 1; i < 15; i ++ ){
			fe[i] = fe[i - 1] * i;
			
		}
		int ans = 1000;
		for(int s = 0; s < (1 << 14); s ++ ){
			int m = n;
			for(int i = 0; i < 14; i ++ ){
				if(s >> i & 1){
					m -= fe[i + 1];
				}
			}
			if(m >= 0) ans = min<int>(ans, __builtin_popcountll(s) + __builtin_popcountll(m));
		}
		cout<<ans<<endl;
	}
	return 0;
}

D Weight the Tree

树形DP,看了好几份代码和官方题解都没有搞明白,感谢xbx大佬的讲解

#include<bits/stdc++.h>

using namespace std;

#define int long long 

const int N = 2e5, M = 2 * N;

int e[M], ne[M], h[M], cnt;

struct Node{
	int v, sum;
}f[N][2];

int T[N];
int dx[N];

void add(int a, int b){
	cnt ++ ;
	e[cnt] = b;
	ne[cnt] = h[a];
	h[a] = cnt;
}

void dfs(int a, int b){
	//f的第一维是这个节点及其子树好节点的个数,第二维是该子树权值之和 
	//f[a][0]是把a节点认为是好顶点的情况,f[a][1]是不把a认为是好节点的情况 
	f[a][0] = {0, 1};//如果a不是好节点,则他的好节点个数为0(此时还没有计算他的子树,姑且认为是0),令a的权值为1,可使整个树的权值之和最小 
	f[a][1] = {1, dx[a]};//如果a是好节点,则他的好节点个数为1,权值就是他的度数 
	for(int i = h[a]; i; i = ne[i]){//遍历子树 
		int j = e[i];
		if(j == b) continue;
		dfs(j, a);
		//如果认定a是好顶点就直接让a的好节点数量和权值之和加上他的该子节点j不是好节点的情况 
		f[a][1].v += f[j][0].v;
		f[a][1].sum += f[j][0].sum;
		//如果认定a不是好节点,就选择他的这个子节点j是/不是好节点两种情况中,好节点更多的情况加到a上 
		if(f[j][0].v > f[j][1].v || (f[j][0].v == f[j][1].v && f[j][0].sum < f[j][1].sum)){
			f[a][0].v += f[j][0].v;
			f[a][0].sum += f[j][0].sum;
		}
		else{
			f[a][0].v += f[j][1].v;
			f[a][0].sum += f[j][1].sum;
		}
	}
}

void build(int a, int b, bool ok){//建树,ok标识a节点是否被认定为好节点 
	if(ok) T[a] = dx[a];//如果a是好节点,则他的权值就是他的度,因为所有非好节点的权值都为1 
	else T[a] = 1;//如果a不是好节点,则a的权值为1 
	for(int i = h[a]; i; i = ne[i]){
		int j = e[i];
		if(j == b) continue;
		if(ok) build(j, a, 0);
		else{
			if(f[j][1].v > f[j][0].v || (f[j][1].v == f[j][0].v && f[j][1].sum < f[j][0].sum)){
				build(j, a, 1);
			}
			else{
				build(j, a, 0);
			}
		} 
		
	}
}
//关键思想:在n!=2的情况下,任意两个相邻的节点只能有一个是好顶点 
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int n;
	cin>>n;
	
	for(int i = 1; i < n; i ++ ){
		int a, b;
		cin>>a>>b;
		dx[a] ++ ;
		dx[b] ++ ;
 		add(a, b);
		add(b, a);
	}
	
	if(n == 2){
		cout<<"2 2"<<endl;
		cout<<"1 1"<<endl;
		return 0;
	}	
	
	dfs(1, -1);
	
	if(f[1][1].v > f[1][0].v || (f[1][0].v == f[1][1].v && f[1][0].sum > f[1][1].sum)){
		cout<<f[1][1].v<<" "<<f[1][1].sum<<endl;
		build(1, -1, 1);
	}
	else{
		cout<<f[1][0].v<<" "<<f[1][0].sum<<endl;
		build(1, -1, 0);
	}
	
	for(int i = 1; i <= n; i ++ ) cout<<T[i]<<" ";
	cout<<endl;
}

小结

能力有限,就先补一下rating<=2000的题吧 这次比赛感觉不错,补题也有收获,继续加油!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值