zoukankan      html  css  js  c++  java
  • AGC005D ~K Perm Counting

    题意简述:如果一个排列P满足对于所有的i都有(|P_i-i| eq k),则称排列P为合法的。现给出n(排列长度)和k,求有多少种合法的排列,对924844033取模。

    clj课件的第一题呢,简单讲下做法。

    首先我们看到计数先考虑容斥,答案可以写成(sum_{i=0}^{n}(-1)^{i}g[i]*(n-i)!),其中(g[i])表示有i个不合法的方案,当前瓶颈在于如何求(g[i])

    然后我们构造一个位置集合和权值集合,发现对于任意一个位置(P),我们将(P)与数值为(P+k,P-k)连边,其与无论是位置还是数值,当且仅当它们对(k)取余相等时,才会对互相造成影响。然后我们容易发现,这是一个左边为位置,右边为权值的二分图,且有一堆互不干扰的链,问题变成了求任选n条边的方案数。我们直接将这些链处理出来,然后设(f[i][j][0/1])表示当前考虑到第(i)个元素,已经选了(j)条边,当前边选或不选,简单转移即可。

    然后(g[i]=f[n*2][i][0]+f[n*2][i][1]),就可以解了。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=2010,mod=924844033;
    int n,k,g[N<<1],f[N<<1][N][2],cnt,fac[N],ans;
    
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;i++){
            for(int j=i;j<=n;j+=k)g[++cnt]=(j==i);
            for(int j=i;j<=n;j+=k)g[++cnt]=(j==i);
        }
        f[0][0][0]=fac[0]=1;
        for(int i=1;i<=n;i++)fac[i]=1LL*i*fac[i-1]%mod;
        for(int i=0;i<n*2;i++)
            for(int j=0;j<=min(i,n);j++){
                f[i+1][j][0]=(f[i][j][0]+f[i][j][1])%mod;
                if(!g[i+1])f[i+1][j+1][1]=f[i][j][0];
            }
        for(int i=0;i<=n;i++){
            int tmp=1LL*(f[n<<1][i][0]+f[n<<1][i][1])*fac[n-i]%mod;
            ans=(mod+(ans+(i&1?-1:1)*tmp)%mod)%mod;
        }
        printf("%d
    ",ans);
    }
    
    

    agc005_d

  • 相关阅读:
    java主函数的含义
    this关键字简单应用
    如何将util.Date转化为sql.Date
    利用JavaScript来实现省份—市县的二级联动
    通过Ajax异步提交的方法实现从数据库获取省份和城市信息实现二级联动(xml方法)
    折半查找(java)(边学习边更新)
    第五章 上
    Jframe关闭窗口时的事件
    C#退出程序自动重新启动
    Extjs4.0 开发笔记与Easyui的整合
  • 原文地址:https://www.cnblogs.com/yxc2003/p/10821998.html
Copyright © 2011-2022 走看看