题解:P10744 [SEERC2020] Modulo Permutations
题目
求有多少个全排列,使
要求长度为
引理
引理:每一个排列从一个位置开始环形遍历,可得到结尾分别为
证:对于
动规
对于其中一个下降子序列,每个数前可接:
我们设
优化
再来一个引理
引理:设
证:对于一个序列结尾为
证毕。
基于引理的快速动规
我们要的答案为
注意
代码
#include<cstdio>
using namespace std;
int n,m,dp[1000009];
int ans;
#define mod 1000000007
int main(){
scanf("%d",&n);
if(n == 1){
puts("1");
return 0;
}
dp[n - 1] = 1;
ans = 1;
for(int i = n - 2; i > 0; i --){
dp[i] = 1;
for(int j = 1; j * i <= n; j ++){
if(j * i > i + 1){ //(i,i + 1) -> (j * i - 1,j * i)
dp[i] = (dp[i] + dp[i * j - 1]) % mod;
}
if(j * i > i && j * i + 1 <= n && i > 1){//(i,i + 1) -> (j * i,j * i + 1)
dp[i] = (dp[i] + dp[i * j]) % mod;
}
if(j * i + 1 > i && j * i + 2 <= n && i > 2){//(i,i + 1) -> (j * i + 1,j * i + 2)
dp[i] = (dp[i] + dp[i * j + 1]) % mod;
}
}
// printf("%d\n",dp[i]);
}
printf("%d\n",1ll * dp[1] * n % mod);
}