题目通道:
https://www.luogu.com.cn/problem/P5784
题目大意:
给你一个数n,表示全为非负数的矩阵大小为3*n,给你3个数$c_{1}$、$c_{2}$、$c_{3}$,分别表示矩阵第一、二、三列的数值之和,再给你n个数,表示第$a_{i}$行的数值之和,请你求出满足条件的矩阵的个数.
solution:
一开始没什么思路,写了手dfs,直觉特判压缩第三列,复杂度O($n^{2}n!$),显然过不去.接着在dfs基础上考虑记忆搜,数组需开到250*150*150,空间较为吃力,时间也有些紧张,代码也不太好写.所以考虑直接递推dp,滚动数组滚掉一个维度,在$1--n$上考虑状态转移,特判维护第三列数值的合法.
code:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define R register #define next exnttttnext #define debug puts("MLG") #define mod 100000000000000000 using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void write(ll x); inline void writesp(ll x); inline void writeln(ll x); ll n,c1,c2,c3; ll num[1000],sum[1000]; ll f[250][250][2]; int main(){ n=read();c1=read();c2=read();c3=read(); for(R ll i=1;i<=n;i++) num[i]=read(),sum[i]=sum[i-1]+num[i]; if(sum[n]!=c1+c2+c3){ writeln(0); return 0; } f[0][0][0]=1; for(R ll i=1;i<=n;i++){ for(R ll j=0;j<=sum[i]&&j<=c1;j++){ for(R ll k=0;k+j<=sum[i]&&k<=c2;k++){ f[j][k][i&1]=0; if(sum[i]-j-k>c3) continue; for(R ll u=0;u<=num[i];u++){ for(R ll v=0;u+v<=num[i];v++){ if(j-u<0||k-v<0||(sum[i]-j-k)-(num[i]-u-v)<0) continue; f[j][k][i&1]+=f[j-u][k-v][(i&1)^1]; f[j][k][i&1]%=mod; } } } } } writeln(f[c1][c2][n&1]); } inline ll read(){ ll x=0,t=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') t=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*t; } inline void write(ll x){ if(x<0){putchar('-');x=-x;} if(x<=9){putchar(x+'0');return;} write(x/10);putchar(x%10+'0'); } inline void writesp(ll x){ write(x);putchar(' '); } inline void writeln(ll x){ write(x);putchar(' '); }