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