• Codeforces340E Iahub and Permutations


    题意:将一个序列的部分变为-1,要求k不能在k位置,已知变化后的序列问原序列有多少种
    题解:不考虑不等于-1的部分,所有等于-1的部分对应的下标,可以分成两部分.
    第一个部分是这个数的下标对应的数字不是-1,也就是说没有限制,有n1个
    第二个部分是这个数的下标对应的数字是-1,也就是说有限制,这个数不能在这里,n2个
    可以想到错排,错排可以用dp递推,也可以用容斥来推,这里用容斥
    设f[i]为至少有i个数相同的序列个数f[i] = c(n2, i)*(n1+n2-i)!
    相同的部分只能是n2中取,剩下的全排列

    那么答案就是求f[0]并去除多余的部分
    ans = f[0]-f[1]+f[2]-....+(-1)^n2*f[n2]
    证明和错排一样,Ai为i在第i位的全排列
    答案就是第一个不为1^第二个不为2....
    摩根定律可以转化上面的式子...就是U-|容斥部分|

    #include <bits/stdc++.h>
    #define ll long long
    #define maxn 100100
    using namespace std;
    const ll mod = 1e9+7;
    ll fc[maxn], fi[maxn], dir1[maxn], dir2[maxn], n, num1, num2, t;
    ll f(ll a,ll b){
        ll ans = 1;
        a %= mod;
        while(b){
            if(b&1) ans = ans*a%mod;
            a = a*a%mod;
            b >>= 1;
        }
        return ans;
    }
    void init(){
        fc[0] = 1;
        for(ll i=1;i<3000;i++) fc[i] = fc[i-1]*i%mod;
        fi[2500] = f(fc[2500], mod-2);
        for(ll i=2500;i>=1;i--) fi[i-1] = fi[i]*i%mod;
    }
    ll c(ll n,ll m){
        if(n<m) return 0;
        return fc[n]*fi[m]%mod*fi[n-m]%mod;
    }
    int main(){
        init();
        scanf("%lld", &n);
        for(ll i=0;i<n;i++){
            scanf("%lld", &t);
            //cout<<t<<endl;
            if(t == -1) num1++, dir1[i+1] = 1;
            else dir2[t] = 1;
        }
        for(int i=1;i<=n;i++)
            if(!dir2[i]&&dir1[i]) num2++;
        ll ans = 0;
        for(int i=0,t=1;i<=num2;i++,t*=-1){
            ans = (mod+ans+t*c(num2, i)*fc[num1-i])%mod;
        }
        printf("%lld
    ", ans);
        return 0;
    }
  • 相关阅读:
    微信小程序demo理解
    HTML 和 JavaScript 编写简单的 404 界面
    阿里云实现简单的运行 Django 项目
    AJAX 与 Python 后台通信
    django session 使用案例
    PHP 基础知识
    Django 搭建后台 favicon.ico 文件操作
    Win10 Ubuntu 双系统 卸载 Ubuntu
    JavaScript 表单验证 案例
    JavaScript Image对象 / Tabel对象 / Select对象 / Form对象
  • 原文地址:https://www.cnblogs.com/Noevon/p/8414288.html
Copyright © 2020-2023  润新知