CSP-S模拟3复盘

T1

题目描述

小 S 喜欢在想象学竞赛网站 CodeFancy 上打比赛。与另一个知名竞赛网站相比,CodeFancy 主要有两点不同:

CodeFancy 上没有 Single Account Policy,即小 S 可以在 CodeFancy 上注册多个账号。
CodeFancy 的 rating 系统更为简单:假设一个 rating 为 x 的用户打了一场比赛,并在其中获得了 y 的表现分,则赛后其 rating 将会更新为 ⌊kx+y/k+1⌋,其中 k 是给定的正整数。
小 S 在 CodeFancy 上有 n 个账号。一个月前,小 S 记录下了这些账号的 rating,其中第 i 个账号的 rating 为 ai。在这个月里,小 S 每次打比赛时,都会选择当前 rating 最低的账号,如果有多个则选择编号最小的。这个月,CodeFancy 共举办了 m 场比赛,其中在第 i 场中小 S 获得的表现分为 bi。现在小 S 想知道他打完这 m 场比赛后每个账号的 rating,但是他懒得登录每个账号查看了。你能帮他求出答案吗?

输入格式

第一行三个正整数 n,m,k。

第二行 n 个非负整数,分别表示 a1,a2,⋯,an。

第三行 m 个非负整数,分别表示 b1,b2,⋯,bm。

输出格式
一行 n 个整数,表示小 S 打完这 m 场比赛后每个账号的 rating。

思路

直接按照题面建造优先队列模拟即可

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define pii pair<int,int>
const int N=2e5+9;
int n,m,k,rat[N];
priority_queue<pii,vector<pii>,greater<pii>> q;
signed main()
{
	cin>>n>>m>>k;
	for (int i=1;i<=n;i++){
		cin>>rat[i];
		q.push({rat[i],i}); 
	}
	for (int i=1;i<=m;i++) {
		int b;
		cin>>b;
		int r=q.top().first,ri=q.top().second;
	//	cout<<ri<<" ";
		q.pop();
		q.push({(k*r+b)/(k+1),ri});
	}	
//	cout<<"\n";
	while(q.size()){
		pii hr=q.top();
		rat[hr.second]=hr.first;
		q.pop();
	}
	for (int i=1;i<=n;i++){
		cout<<rat[i]<<" ";
	}
	return 0;
}

T2

题目描述

小 S 是一位武术爱好者,他最近迷上了练习三截棍。为了更好地理解三截棍的结构,小 S 决定从一棵拥有 n 个节点的树中寻找灵感。他打算从这棵树中选取一条长度为 3 的简单无向路径,构成一根三截棍。也就是说,这条路径包含 4 个不同的节点,并且 (a,b,c,d) 和 (d,c,b,a) 被看作是同样的三截棍。他想知道一共能选出多少种不同的三截棍,但是又懒得亲自算了。你能帮他解决这个问题吗?

输入格式

第一行一个正整数 n。

接下来 n−1 行每行两个正整数 u,v,表示树上的一条边。

输出格式

一行一个非负整数,表示能选出的不同三截棍的数量。

思路

dfs遍历整棵树,求出每个节点的父亲和儿子节点总和相乘后累加就是答案

代码

#include<bits/stdc++.h>
using namespace std;
vector<int> g[(int)2e5+9];
int n,ans,son[(int)2e5+9];
void dfs(int u,int fa){
	int res=0;
	for (int i:g[u]){
		if (i!=fa){
			son[u]++;
			dfs(i,u);
			res+=son[i];
		}
	}
	ans+=1ll*res*(g[u].size()-1);
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
	for (int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v),g[v].push_back(u);
	}
	dfs(1,0);
	cout<<ans;
	return 0;
}

T3

题目描述

小 S 有一棵 n 个节点的树,他想从其中选取一条长度为 3 的简单无向路径,构成一根三截棍。经过你的帮助,他知道了一共能选出 k 种不同的三截棍。可是,粗心的小 S 把他的树弄丢了,所以他希望你再帮他找出一棵树,使得其中恰好能选出 k 种不同的三截棍。他还需要你找出的树的大小在 [1,500] 上,否则他就无法把这棵树带回家了。

输入格式

第一行一个非负整数,表示 k。

输出格式

第一行一个正整数 n。

接下来 n−1 行每行两个正整数 u,v,表示树上的一条边。

思路

先在1下面挂若干条长度2的链,假设挂了c条,则贡献为 c(c-1),因为任意选择两条链,它们的贡献为2 。当再加链就要超过k时,
就开始在其中一条链的底下继续挂点,每挂一个点,其贡献都1。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
signed main()
{
	cin>>n;
	int a=0,b=0,c=0,res=1;
	while(a*(a+1)<=n) a++;
	while(a*(a+b)<=n) b++;
	c=n-a*(a+b-1);
	a-=c;
	cout<<1+a*2+c*3+b<<"\n";
//	cout<<a<<" "<<b<<" "<<c<<"\n";
	for (int i=1;i<=c;i++){
		cout<<"1 "<<++res<<"\n";
		cout<<res<<" "<<res+1<<"\n";
		res++;
		cout<<res<<" "<<res+1<<"\n";
		res++;
	}
	for (int i=1;i<=a;i++){
		cout<<"1 "<<++res<<"\n";
		cout<<res<<" "<<res+1<<"\n";
		res++; 
	}
	for (int i=1;i<=b;i++) cout<<1<<" "<<++res<<"\n";
	return 0;
}

T4

还不会,先滤过QAQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值