求满足以下条件的长为 的排列 的个数:
- 对于所有 有 ;
- ;
。
首先去掉 和 之后,完美的排列显然可以分成两段下降的序列 和 ,它们之间需要用 和 拼起来。
观察到显然 这样的一段连续序列一定是合法的,那么去掉 和 之后的序列 一定可以分成若干段,第 段分给 并且互相连接,第 段分给 并且互相连接。
考虑动态规划,设 表示 划分好了,最后一段以 开头的方案数,那么考虑以 开头的那一段前面是哪一段,有转移:
其中 是因为 划分为一整段一定是合法的。
最后的答案即为 ,因为 这一段需要另外算,并且 和 可以任意交换顺序且环可以转。
代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
#define fio(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)
const int S=1000005,p=1000000007;
int n,dp[S];
inline void add(int &x,int y)
{
x+=y;
if(x>=p) x-=p;
}
int main()
{
fio("permutation");
scanf("%d",&n);
if(n<=2) return printf("%d\n",n),0;
int ans=1;
for(int i=n-1;i>=3;i--)
{
int tmp=1;
for(int j=i;j<=n;j+=i) add(tmp,((long long)dp[j-1]+dp[j]+dp[j+1])%p);
dp[i]=tmp;
add(ans,dp[i]);
}
printf("%d\n",1ll*ans*2%p*n%p);
return 0;
}