第一问,考虑添加第i个数能造成的影响,f[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+...+f[i-1][j]
第二问,对于val[p]=v的地方,从v向p连一条有向边,形成一个由几个环组成的有向图(类似置换?)
每次交换最多减少一个环,所以最多减少Max(0,n-m)个环,而n个数排成m个环(圆排列)就是第二类斯特林数s[n][m]
- s[n][m]=s[n-1][m-1]+(n-1)*s[n-1][m]
- 理解:当前的数可以新成一个环,也可以插入到之前的环中的n-1个位置
#include<iostream> #include<cstring> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MOD = 1000000007; const int MAXN = 4096; typedef long long ll; int n,m,num; ll s[2][MAXN]; ll f[2][MAXN]; int main(){ n=rd();m=rd(); f[0][0]=1ll; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++){ f[i&1][j]=f[(i+1)&1][j]; if(j-i>=0)f[i&1][j]-=f[(i+1)&1][j-i]; while(f[i&1][j]<0) f[i&1][j]+=MOD; f[i&1][j]%=MOD; } for(int j=1;j<=m;j++) f[i&1][j]=(f[i&1][j]+f[i&1][j-1])%MOD; } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(j==i){s[i&1][j]=1;continue;} s[i&1][j]=s[(i+1)&1][j-1]+(1ll*i-1ll)*s[(i+1)&1][j]; s[i&1][j]%=MOD; } } ll ans=0ll; for(int i=m;i>=0;i-=2){ ans+=f[n&1][i];ans%=MOD; } cout<<ans<<" "; ans=0ll; for(int i=n;i>=n-m;i--){ ans+=s[n&1][i]; ans%=MOD; } cout<<ans; return 0; }