码迷,mamicode.com
首页 > 其他好文 > 详细

AGC 005D.~K Perm Counting(容斥 DP 二分图)

时间:2018-12-10 14:04:04      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:枚举   链接   不同   long   class   dal   desc   tps   const   

题目链接

\(Description\)

给定\(n,k\),求 满足对于所有\(i\)\(|a_i-i|\neq k\)的排列的个数。
\(2\leq n\leq 2000,\quad 1\leq k\leq n-1\)

\(Solution\)

容斥。则\(Ans=\sum_{i=0}^n(-1)^ig(i)(n-i)!\),其中\(g(i)\)为至少有\(i\)个位置满足\(|a_i-i|=k\)的排列数。

考虑如何计算\(g(x)\)。每个\(i\)\(i+k\)\(i-k\)连边,可以得到一张二分图,\(g(x)\)就是在这张二分图上选\(x\)个匹配的方案数。

我们还可以发现,图中的匹配形成了\(2k\)条互不相交的链,且每条链上的数模\(k\)相同(也就是模\(k\)不同的数是互不影响的,所以枚举模数就可以得到所有链了)。

如果只有一条长\(l\)的链,那么就是对\(l-1\)个点DP,\(f[i][j][0/1]\)表示当前第\(i\)个点,已经选了\(j\)个匹配,这个点选不选(这个点选要求上一个点没选)。
对于\(2k\)条链也是一样的,只要在链之间加一个点,并强制它不能选(\(f[i][j][1]=0\)),就可以把这些链合在一起DP啦。

这样复杂度\(O(n^2)\),然而好多dalao用NTT\(n\log n\)过掉了orz。


因为想跑快点(个人习惯)写的有点乱,代码也可以看他的:http://www.cnblogs.com/wxjor/p/9476998.html

//20ms  256KB
#include <cstdio>
#include <algorithm>
#define mod 924844033
typedef long long LL;
const int N=4005;//2n

int ban[N],f[2][N][2],fac[N];

int main()
{
    int n,K,cnt=0; scanf("%d%d",&n,&K);
    for(int i=1; i<=K; ++i)
    {
        ban[++cnt]=1;
        for(int j=i+K; j<=n; j+=K) ban[++cnt]=0;
        ban[++cnt]=1;//就是两条链啊 
        for(int j=i+K; j<=n; j+=K) ban[++cnt]=0;
    }
    int p=0; f[p][0][0]=1;
    for(int i=0; i<cnt; ++i,p^=1)
        for(int j=0; j<=i; ++j)
        {
            f[p^1][j][0]=(f[p][j][0]+f[p][j][1])%mod;
            if(!ban[i+1]) f[p^1][j+1][1]=f[p][j][0];
            f[p][j][0]=f[p][j][1]=0;
        }
    fac[0]=1;
    for(int i=1; i<=n; ++i) fac[i]=1ll*fac[i-1]*i%mod;
    LL ans=0;
    for(int i=0; i<=n; ++i)
        ans+=i&1?mod-1ll*fac[n-i]*(f[p][i][0]+f[p][i][1])%mod:1ll*fac[n-i]*(f[p][i][0]+f[p][i][1])%mod;
    printf("%lld\n",ans%mod);

    return 0;
}

AGC 005D.~K Perm Counting(容斥 DP 二分图)

标签:枚举   链接   不同   long   class   dal   desc   tps   const   

原文地址:https://www.cnblogs.com/SovietPower/p/10095512.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!