Justin0779
2024-11-16 19:57:57
我十分支持出题人改人名的行为(因为省选真的很难
入手之后看题,不难发现这个随机是没有用的,在无限轮的加持下,Aob 会选完所有可能的逆序对或逆序对下标,即
这样我们稍微知道了我们需要求的是什么,但进入计算还是很遥远不好想,我们从样例入手:
3
0 2 0
它的答案是
7
0 3 2 0 5 7 0
它的答案是
同时,我们自己构造一个数据
3
2 1 3
他的答案是
然后观察三组数据(也可以结合
对于位置
x ,要么有x=p_x ,要么有p_{p_x}=x
这就是我们所发现的性质,即两两必然配对(相等的情况算广义)。然后我们从
有了这个性质,我们的前路豁然开朗。剩下的工作便只有判无解和推出有
剩下就是考虑推出有解的答案。令
考虑 DP,尝试写出转移方程,我们要由
转移方程即为:
这道题到这里就做完了,时间复杂度
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int N = 1e6 + 514;
constexpr ll mod = 998244353;
namespace Otakus
{
int n, a[N], A[N], cnt = 0;
ll dp[N];
void init()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
if (i != a[i] && a[i] != 0)
{
if (!a[a[i]])
a[a[i]] = i;
else if (a[a[i]] != i)
{
cout << 0;
return;
}
}
}
for (int i = 1; i <= n; i++)
if (!a[i])
cnt++;
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= cnt; i++)
dp[i] = (dp[i - 1] + (i - 1) * dp[i - 2]) % mod;
cout << dp[cnt];
}
} // namespace Otakus
int main()
{
Otakus::init();
return 0;
}