[51nod] 1250 排列与交换

第一问,考虑添加第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;
}
未经许可,禁止搬运。
原文地址:https://www.cnblogs.com/ghostcai/p/9606775.html