补题:河南萌新联赛2024第(四)场:河南理工大学

目录

C-岗位分配

I-马拉松


C-岗位分配

思路:采用隔板法,对于需求为k的岗位,提前安排k-1个人,计算所有提前插入的总人数sum,在m-sum和m-sum-1中加入隔板,有空闲的情况就是在m-sum-1中放n个隔板,答案为两种情况之和。

代码:

#include<bits/stdc++.h>
using namespace std;
using ll =long long ;
#define int long long
#define INF 0x3f3f3f3f
const int N=1e5+5;
const int maxn=1e5+5;
const int mod=998244353;
ll inv[maxn], fac[maxn];  //分别表示逆元和阶乘
//快速幂
ll quickPow(ll a, ll b) {
	ll ans = 1;
	while (b) {
		if (b & 1)
			ans = (ans * a) % mod;
		b >>= 1;
		a = (a * a) % mod;
	}
	return ans;
}
void init() {
	//求阶乘
	fac[0] = 1;
	for (int i = 1; i < maxn; i++) {
		fac[i] = fac[i - 1] * i % mod;
	}
	//求逆元
	inv[maxn - 1] = quickPow(fac[maxn - 1], mod - 2);
	for (int i = maxn - 2; i >= 0; i--) {
		inv[i] = inv[i + 1] * (i + 1) % mod;
	}
}
ll C(int n, int m) {
	if (m > n) {
		return 0;
	}
	if (m == 0)
		return 1;
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void solve()
{
	init();
	int n, m;
	cin>>n>>m;
	int sum = 0;
	for (int i = 0; i < n; i++) {
		int a;
		cin >> a;
		sum += a - 1;
	}
	m -= sum;
	ll ans=C(m - 1, n) + C(m - 1, n - 1);ans%=mod;
    cout<<ans;

}
signed main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    // int _;cin>>_;while(_--)
    solve();
}

I-马拉松

思路:如果将顶点 y 作为树根,那么可以知道小明不能正常比赛的马拉松的每一对顶点都是从节点 x 的子树内 的任意节点开始,并在节点y的子树且不包括在节点 z(节点 z 是 y 的直子节点,位于从 x 到 y 的最短路 径上)的子树内的任意节点结束。我们要找的顶点对的总数等于 s[x]·(s[y] - s[z]) ,其中 s[i] 表示节点 i 的 子树的大小,t表示的是y的直子节点,且该点可以使用 DFS 来实现。

代码:

#include <iostream>
 #include <vector>
 using namespace std;
 const int N=3e5+10;
 vector<int> g[N];
 bool st[N];
 long long sun[N];
 bool check[N];

int n,x,y;
 long long dfs(int u)
 {
    st[u]=1;
    sun[u]=1;
    if(u==x)check[u]=1;
    
    for(int i:g[u])
    {
        if(!st[i])
        {
            sun[u]+=dfs(i);
            check[u]|=check[i];
        }
    }
    return sun[u];
 }
 int main()
 {
    cin>>n>>x>>y;
    int m=n-1;
    for(int i=0,u,v;i<m;i++)
    {
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(y);
    long long find=0;
    for(int i:g[y])
    {
        if(check[i]==1)
        {
            find=sun[y]-sun[i];
        }
    }
    long long ans=find*sun[x];
    cout<<ans<<endl;
 }

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值