P5784 [CQOI2008] 矩阵的个数

题意

给定一个 $n\times3$ 的矩阵的各行各列之和,求满足条件的矩阵的个数。

Solution

计数题,考虑朴素 dp,定义 $f_{i,a,b,c}$ 为当前枚举到第 $i$ 行,每列之和分别为 $a$,$b$,$c$ 时的方案数。枚举当前列所填数,令其分别为 $now_1$,$now_2$,$now_3$ 则有转移方程:$$ \large{f_{i,a,b,c}\gets f_{i-1,a-now_1,b-now_2,c-now_3}} $$ 由于各行,列之和均小于等于 $125$,故每行之和 $val_i$ 大约在 $\frac{125\times 3}{n}$ 左右,每列之和 $sum_i$ 不超过 $125$,故朴素 dp 复杂度约为 $\mathcal{O}(n\times val^3\times sum^3)$,无法在时限内通过本题。故考虑优化。

发现当 $a$,$b$ 确定时,$c$ 也确定,故由此可通过前缀和将第四位优化掉,$now_1$,$now_2$,$now_3$ 同理。故当满足 $\sum^{i}_{k=1}sum_k-a-b \ge 0$ 且 $sum_i-now_1-now_2 \geq 0$ 时有转移方程:$$ \large{f_{i,a,b}\gets f_{i-1,a-now_1,b-now_2}} $$ 最坏时间复杂度约为 $\mathcal{O}(n\times val^2\times sum^2)$ ,可以通过本题。

code

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int res=0,flag=1;
    char ch=getchar();
    while(!isalnum(ch)) (ch=='-')?flag=-1:1,ch=getchar();
    while(isalnum(ch)) res=res*10+ch-'0',ch=getchar();
    return res*flag;
}
int val[210];
long long dp[210][210][210];
int main(int argc,const char *argv[])
{
    int n=read();
    int s1=read(),s2=read(),s3=read();
    for(int i=1;i<=n;i++)
         val[i]=read();
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++)
        for(int n1=0;n1<=s1;n1++)
            for(int n2=0;n2<=s2;n2++)
                for(int d1=0;d1<=n1&&d1<=val[i];d1++)
                    for(int d2=0;d2<=n2&&d1+d2<=val[i];d2++)
                        dp[i][n1][n2]=(dp[i][n1][n2]+dp[i-1][n1-d1][n2-d2])%(long long)1e17;
    printf("%lld",dp[n][s1][s2]);
    return 0;
}

写在最后

三年 OI 一场空,不开 long long 见祖宗

posted @   Che_001  阅读(22)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示