专栏文章
题解:AT_abc226_f [ABC226F] Score of Permutations
AT_abc226_f题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miod13q8
- 此快照首次捕获于
- 2025/12/02 17:12 3 个月前
- 此快照最后确认于
- 2025/12/02 17:12 3 个月前
Solution
考虑每个人 向自己的 连边,由于 是一个排列,所以每个点入度为 ,出度为 ,也就是说图由若干个环组成。进一步地,每个环在变换它的大小的次数后会恢复原样,因此对于一个排列 连成的图, 等于所有环的大小的 。
对于计算答案,可以考虑枚举有一些什么样的环。更具体地,从大到小 dfs 枚举环的大小加入答案。当我们加入一个大小为 的环时,相当于从剩下的点里选 个,让它们组成圆排列,注意如果有若干个大小相同的环,还要减去这些环重复的情况。细节可结合代码理解。
由于我们是从大到小枚举环,dfs 的次数是不多的。经测试,当 时,一共进行了 次 dfs。
Code
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 55,M = 998244353;
int n,k,fac[N],ifac[N],ans;
int qpow(int a,int b)
{
int ret = 1;
while (b)
{
if (b&1) (ret *= a) %= M;
(a *= a) %= M;
b >>= 1;
}
return ret;
}
inline int inv(int a)
{
return qpow(a,M-2);
}
inline int C(int a,int b)
{
return fac[a]*ifac[b]%M*ifac[a-b]%M;
}
inline int cirA(int a,int b)
{
return fac[a]*ifac[a-b]%M*inv(b)%M;
}
int gcd(int a,int b)
{
if (!b) return a;
return gcd(b,a%b);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
void dfs(int u,int num,int sum,int p,int lc)
{
if (!num)
{
(ans += sum*ifac[p]%M*qpow(lc,k)) %= M;
return;
}
if (num >= u) dfs(u,num-u,sum*cirA(num,u)%M,p+1,lcm(lc,u));
for (int i = 1; i <= min(u-1,num); i++)
dfs(i,num-i,sum*cirA(num,i)%M*ifac[p]%M,1,lcm(lc,i));
}
signed main()
{
ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
fac[0] = ifac[0] = 1;
for (int i = 1; i < N; i++)
fac[i] = fac[i-1]*i%M,ifac[i] = inv(fac[i]);
cin >> n >> k;
dfs(n,n,1,0,1);
cout << ans;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...