zoukankan      html  css  js  c++  java
  • CSP-S2019 Emiya 家今天的饭

    原题

    题意分析

    给出一个矩阵,要求每行只能选一个节点,每列选的节点不能超过所有选的节点的一半,不能不选,给出每个节点的选择方案数,求总方案数

    思路分析

    可以看出,维护每列已选的节点复杂度太大,不太可行;因此很容易想到,先不考虑每列不超过一半的这个限制,求出总方案数,然后再减去考虑这个限制后不合法的方案数。现在问题就变成,求任意列选的节点超过所有选的节点的一半的方案数之和。

    显然,在一个方案中,只可能有一列的节点超过所有选的节点的一半。因此可以想到枚举这个超过限制的列,然后对于这个列进行DP求解。

    具体实现

    f_{i,j,k}fi,j,k表示前ii行选jj个节点,当前枚举到的列选kk个节点的方案数。对于每个列,复杂度为O(n^3)O(n3),总的复杂度为O(mn^3)O(mn3),可以得到84分的高分。

    想得到满分还需要进一步优化。考虑将某两个状态合并。观察状态,实际上我们想知道的只是j,kj,k的大小关系,对于具体的值并不关心,考虑将它们合并到一维。

    考虑我们需要的限制条件k>left lfloor frac{j}{2} ight floork>2j⌋,变形一下可以得到2k+n-j>n2k+nj>n。观察这个式子,可以发现,n-jnj就是这nn行里没有选的行数。然后一个奇妙的想法就出来了,对于每个节点,选它时当做该列选了两次,而对于某一行不选时,当做所有列选了一次,最终要找的就是当前列被选超过nn次的方案。这样就成功地优化掉了第二维。

    给一下状态转移方程:

    f[j][k]=(f[j][k]+f[j-1][k]*(cnt[j]-w[j][i]))%P;//不选当前列
    f[j][k+1]=(f[j][k+1]+f[j-1][k])%P;//不选当前行
    f[j][k+2]=(f[j][k+2]+f[j-1][k]*w[j][i])%P;//选当前行当前列对应的节点

    注意取模时出现负数的情况,记得开long long

    #include<bits/stdc++.h> 
    #define ll long long
    using namespace std;
    const int N=205,M=2005,MOD=998244353;
    int n,m;
    ll ans=1,cnt[N],w[N][M],f[N][M];
    int main() {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) {
            for (int j=1;j<=m;j++) {
                scanf("%lld",&w[i][j]);
                cnt[i]=(cnt[i]+w[i][j])%MOD;
            }
            ans=(ans*(cnt[i]+1))%MOD;
        }
        ans=(ans+MOD-1)%MOD;
        for (int i=1;i<=m;i++) {
            memset(f,0,sizeof(f));
            f[0][0]=1;
            for (int j=1;j<=n;j++)
                for (int k=0;k<=2*(j-1);k++) {
                    f[j][k]=(f[j][k]+f[j-1][k]*(cnt[j]-w[j][i]))%MOD;
                    f[j][k+1]=(f[j][k+1]+f[j-1][k])%MOD;
                    f[j][k+2]=(f[j][k+2]+f[j-1][k]*w[j][i])%MOD;
                }
            for(int j=n+1;j<=2*n;j++)
                ans=(ans+MOD-f[n][j])%MOD;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    DS博客作业02--栈和队列
    DS博客作业01--线性表
    c博客06-结构体&文件
    C博客作业05--指针
    C语言博客作业04--数组
    C语言博客作业03--函数
    JAVA面向对象设计大作业——QQ联系人系统
    DS博客作业05--查找
    DS博客作业04--图
    DS博客作业03--树
  • 原文地址:https://www.cnblogs.com/zzrblogs/p/12201995.html
Copyright © 2011-2022 走看看