zoukankan      html  css  js  c++  java
  • codeforces 277.5 div2 F:组合计数类dp

    题目大意:

    求一个 n*n的 (0,1)矩阵,每行每列都只有两个1 的方案数

    且该矩阵的前m行已知

    分析:

    这个题跟牡丹江区域赛的D题有些类似,都是有关矩阵的行列的覆盖问题

    牡丹江D是求概率,这个题是方案数,也比较相似。。

    这种题中,因为只要求方案数。。我们只要关注几行几列有几个1,而不必要关注具体的位置

    题解:

    行列都需要处理,因此考虑记录列的状态,然后一行一行的转移

    最暴力的方程:

    dp[i][j][k][t] 表示已经确定了 i 行 有 j列已经有两个1,有k列只有一个1,有t列一个1也没有的方案数

    很显然 第i+1行的两个1 只能放在k列中 或者 t列中

    状态转移方程乘上组合数也是很好写的

    但是这个方程显然过于暴力。。需要优化

    首先,显然 j+k+t=n 因此 t 就不用枚举了

    方程变为n3,由于cf服务器很强大,已经可以过了。。

    然后又发现 ,前 i 行 应该有且只有 2i 个1 ,所以显然 k=2* i - j

    k也不用枚举了。。

    最终得到一个二维的dp

    代码如下:

    #include <iostream>
    #include <stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<string>
    #include<ctype.h>
    using namespace std;
    #define MAXN 10000
    int n,m,mod;
    int dp[2][501];
    char s[501];
    int num[501];
    void ini()
    {
        memset(num,0,sizeof(num));
        //memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
        {
            scanf("%s",s);
            for(int i=0;i<n;i++)
            {
                num[i]+=s[i]-'0';
            }
        }
        int j=0;
        for(int i=0;i<n;i++)
        {
            if(num[i]==2)
                j++;
        }
        dp[m%2][j]=1;
    }
    void solve()
    {
        for(int i=m+1;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
            {
                if(!dp[(i-1)%2][j])
                    continue;
                int k=2*(i-1)-2*j;
                int t=n-j-k;
                if(k<0)
                    break;
                if(j<=n-2&&k>=2)
                {
                    dp[i%2][j+2]+=(long long)dp[(i-1)%2][j]*k*(k-1)/2%mod;
                    dp[i%2][j+2]%=mod;
                }
                if(t>=2)
                {
                    dp[i%2][j]+=(long long)dp[(i-1)%2][j]*(t)*(t-1)/2%mod;
                    dp[i%2][j]%=mod;
                }
                if(t&&k)
                {
                    dp[i%2][j+1]+=(long long)dp[(i-1)%2][j]*(t)*k%mod;
                    dp[i%2][j+1]%=mod;
                }
                dp[(i-1)%2][j]=0;
            }
        }
        printf("%d
    ",dp[n%2][n]);
    }
    int main()
    {
        while(scanf("%d%d%d",&n,&m,&mod)!=EOF)
        {
            ini();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    iOS应用程序间共享数据(转)
    解决右滑返回手势和UIScrollView中的手势冲突(转)
    (转)iOS被开发者遗忘在角落的NSException-其实它很强大
    iOS 身份证最后一位是X,输入17位后自动补全X(转)
    springboot单机秒杀之queue队列
    springboot单机秒杀-aop+锁
    springbot单机秒杀,锁与事务之间的大坑
    spring-cloud学习之4.微服务请求打通
    spring-cloud学习之3.使用feign实现负载均衡
    spring-cloud学习之2.搭建请求网关spring-cloud-getway
  • 原文地址:https://www.cnblogs.com/oneshot/p/4106564.html
Copyright © 2011-2022 走看看