2021牛客寒假算法基础集训营5 比武招亲(上)(组合数学)
比武招亲(上)
https://ac.nowcoder.com/acm/contest/9985/B
Description
Solution
本人不擅长组合数学,因此只能打表找规律
map<vector<int>, int> mp;
void dfs(int now, vector<int> v) {
if (now == m) {
sort(v.begin(), v.end());
if (mp[v]) {
return ;
}
mp[v]++;
ans += v.back() - v[0];
vis[v.back() - v[0]]++;
cout << v.back() - v[0] << ' ';
return ;
}
for (int i = 1; i <= n; i++) {
v.emplace_back(i);
dfs(now + 1, v);
v.pop_back();
}
}
void solve() {
vector<int> v;
dfs(0, v);
for (auto &it : vis) { // 这里可以看出每个数字出现了多少次
cout << it.first << ' ' << it.second << '\n';
}
cout << ans << '\n';
}本题的答案由两个变量 决定,直接找规律有难度
因此不妨用控制变量法,即固定 的值,对
进行变化
不难得到 的时候只会出现
的贡献,
的时候只会出现
的贡献 ....
于是通过改变 的值去看
时
的贡献随
的变化规律,
时
的贡献随
的变化规律
不难得到规律:
的贡献为
的贡献为
的贡献为
对于前面分数的分子可以用前缀积 O(1) 计算, 分母是阶乘, 除法取模的时候乘上阶乘的逆元即可。
因为我是用快速幂求逆元,时间复杂度
再预处理下逆元可以
Code
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 1e6 + 5;
const int mod = 998244353;
int n, m;
int ans = 0;
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) {
res = res * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return res;
}
ll M[N], f[N];
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int T = 1; //cin >> T;
while(T--) {
cin >> n >> m;
M[1] = m - 1; // 前缀积
for (int i = 2; i <= 5e5; i++) {
M[i] = M[i - 1] * (m - 2 + i) % mod;
}
f[0] = 1; // 阶乘
for (int i = 1; i <= 5e5; i++) {
f[i] = f[i - 1] * 1LL * i % mod;
}
ll res = 0;
for (int i = 1; i <= n - 1; i++) {
res += 1LL * i * M[i] % mod * qpow(f[i], mod - 2) % mod * (n - i) % mod;
res %= mod;
}
cout << res << '\n';
}
return 0;
}
迅雷公司福利 193人发布
