nowcoder15614 队列重排

链接

https://ac.nowcoder.com/acm/problem/15614

题解

可以发现,当我把两个相邻的数字捆绑在一起的时候,联通块少了一个,原先有 n n 个联通快,假设有 t t 个数字是「“重排后前方” 跟 “原排列前方” 一样的人」的,那么这样联通块个数就成了 n t n-t

那么接下来我想求出, x x 个联通块,重排之后,每个都不能和他原先相邻的那个联通块相邻,有多少种方案。不妨记作 f ( x ) f(x) 。考虑从前往后依次加入每个联通块,那么第 x x 个联通块不能放在第 x 1 x-1 个联通块的后面,这样分析,得到一个假的递推式: f ( x ) = x f [ x 1 ] f(x)=x*f[x-1] 。你会发现算出来的结果太小了,因为少算了 1 , 3 , 2 1,3,2 这种,因为 f [ 2 ] f[2] 中不包含 1 , 2 1,2 这样的方案,所以自然插入第三个数字的时候也不会出现 1 , 3 , 2 1,3,2 这种方案。这个其实很好解决,我就是想算上那种第 i i 个数字插入之后破坏了之前的相邻关系,并且最后没有相邻关系的,那么我就选两个数字让他们相邻。再把 i i 这两个数字之间就好了,这部分方案的贡献是 ( i 2 ) f [ i 2 ] (i-2)*f[i-2]

于是 f [ i ] = ( i 2 ) f [ i 2 ] + ( i 1 ) f [ i 1 ] f[i]=(i-2)f[i-2]+(i-1)f[i-1]

答案
a n s = t = 0 k C ( n 1 , t ) f [ n t ] ans = \sum_{t=0}^k C(n-1,t) * f[n-t]

代码

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(_,__) for(_=1;_<=(__);_++)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl;
#define mod 1000000007ll
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct EasyMath
{
    ll prime[maxn];
    bool mark[maxn];
    ll fastpow(ll a, ll b, ll c)
    {
        ll t(a%c), ans(1ll);
        for(;b;b>>=1,t=t*t%c)if(b&1)ans=ans*t%c;
        return ans;
    }
    void get_prime(ll N)
    {
        ll i, j;
        for(i=2;i<=N;i++)mark[i]=false;
        *prime=0;
        for(i=2;i<=N;i++)
        {
            if(!mark[i])prime[++*prime]=i;
            for(j=1;j<=*prime and i*prime[j]<=N;j++)
            {
                mark[i*prime[j]]=true;
                if(i%prime[j]==0)break;
            }
        }
    }
}em;
ll fact[maxn], _fact[maxn], n, f[maxn], ans;
ll C(ll n, ll m)
{
    return fact[n]*_fact[m]%mod * _fact[n-m] %mod;
}
int main()
{
    ll i, n=read(), k=read();
    fact[0]=_fact[0]=1;
    rep(i,n)fact[i]=fact[i-1]*i%mod, _fact[i]=em.fastpow(fact[i],mod-2,mod);
    f[1]=f[2]=1;
    for(i=3;i<=n;i++)f[i]=(f[i-2]*(i-2)+f[i-1]*(i-1))%mod;
    for(i=0;i<=k;i++)(ans+=C(n-1,i)*f[n-i])%=mod;
    printf("%lld",(ans+mod)%mod);
    return 0;
}
发布了863 篇原创文章 · 获赞 72 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/104058180