20200720T1【CQOI2008】矩阵的个数(洛谷 P5784)

Description

给出一个N行3列非负整数矩阵的各行各列之和,统计有多少个矩阵满足此条件。输出答案模10^17的值。

Input

第一行包含四个正整数N,c1, c2, c3,即行数与三列之和。第二行包含N个正整数,即各行三个数之和。每行每列之和均不超过125。

Output

仅一个数,满足条件的矩阵个数模10^17的值。

Sample Input

3 2 3 4
1 2 6

Sample Output

17

Hint

 1<=N<=200

 Solution

T1一看就没思路,丢给zjy1412打了手暴力dfs

 1 void dfs(int x,int l1,int l2,int l3){
 2     if(x==n){
 3         ans++;
 4         if(ans>=P)ans-=P;//其实没必要了,等你运行到1e17.........
 5         return;
 6     }
 7     for(int i=(l1<d[x]?l1:d[x]);i>=0;i--){
 8         if(l2+l3<d[x]-i)break;
 9         for(int j=(l2<d[x]-i?l2:d[x]-i);j>=0;j--){
10             if(l3<d[x]-i-j)break;
11             dfs(x+1,l1-i,l2-j,l3-(d[x]-i-j));
12         }
13     }
14 }
//dfs(1,c1,c2,c3);

答案都要模1e17,显然T飞

起码还有30points

 

正解是DP

f[i][j][k]表示前i行第一列和为j,第二列和为k的方案数

一行就三个数,知道两个另外一个也就知道了

f[i][j][k]=∑ f[i-1][j-x][k-y]

f[0][0][0]=1

x和y表示这一行第一列放x,第二列放y

发现i只与i-1有关,所以可以滚掉一维

判断一下j,k,c3+j+k,x,y的条件即可

code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<queue>
 7 #include<vector>
 8 #include<stack>
 9 #include<set>
10 #include<deque>
11 #include<map>
12 using namespace std;
13 
14 template <typename T> void read(T &x) {
15     x = 0; int f = 1; char c;
16     for (c = getchar(); c < '0' || c > '9'; c = getchar()) if (c == '-') f = -f;
17     for (; c >= '0' && c <= '9'; c = getchar()) x = 10 * x + c - '0' ;
18     x *= f;
19 }
20 template <typename T> void write(T x){
21     if (x < 0) putchar('-'), x = -x;
22     if (x > 9) write(x / 10);
23     putchar(x % 10 + '0');
24 }
25 template <typename T> void writeln(T x) { write(x); putchar('\n'); }
26 template <typename T> void writesn(T x) { write(x); putchar(' '); }
27 
28 #define int long long
29 #define inf 1234567890
30 #define next net
31 #define P 100000000000000000
32 #define N 205
33 #define mid ((l+r)>>1)
34 #define lson (o<<1)
35 #define rson (o<<1|1)
36 #define R register
37 
38 int n,c1,c2,c3,d[N],top[N],ans;
39 int f[N][N][2];
40 signed main(){
41     read(n);read(c1);read(c2);read(c3);
42     for(R int i=1;i<=n;i++)read(top[i]),d[i]=d[i-1]+top[i];
43     f[0][0][0]=1;
44     for(R int i=1;i<=n;i++){  //先枚举所有状态j,k
45         for(R int j=0;j<=c1 && j<=d[i];j++){
46             for(R int k=0;k<=c2 && j+k<=d[i];k++){//注意j,k是这一列的和
47                 f[j][k][(i&1)]=0;
48                 if(c3+j+k<d[i])continue;  //再枚举转移x,y
49                 for(R int x=0;x<=j && x<=top[i];x++){//x,y才是这一行填的数
50                     for(R int y=0;y<=k && x+y<=top[i];y++){
51                         f[j][k][(i&1)]+=f[j-x][k-y][(i&1)^1];
52                         f[j][k][(i&1)]%=P;
53                     }
54                 }
55             }
56         }
57     }
58     writeln(f[c1][c2][n&1]);
59     return 0;
60 }

 

posted @ 2020-07-20 15:23  e_e_thinker  阅读(153)  评论(0编辑  收藏  举报