codeforces Diagrams & Tableaux1 (状压DP)

http://codeforces.com/gym/100405

D题

题在pdf里

codeforces.com/gym/100405/attachments/download/2331/20132014-acmicpc-northwestern-european-regional-contest-nwerc-13-en.pdf

 

D - Diagrams & Tableaux
A Young diagram is an arrangement of boxes in rows and columns conforming to the following
rules:
the boxes in each row and each column are contiguous,
the left borders of all rows are aligned, and
each row is not longer than the one above.
Here are some examples of Young diagrams:
A semi-standard Young tableau for a given number N is a Young diagram that has its boxes
filled according to the following rules:
Each box contains a single integer between 1 and N, inclusive,
each integer is greater than or equal to the integer in the box to its left, and
each integer is strictly greater than the integer in the box above.
Here is a list of all semi-standard Young tableaux for N = 3, based on a particular Young
diagram:
1
2
1 1
3
1 1
2
2 1
3
2 1
2
3 1
3
3 2
3
2 2
3
3
Your task is to count how many semi-standard Young tableaux are possible, based on a given
Young diagram, with a given N.
Input
Each test case consists of two lines. The first line of each test case specifies the Young diagram.
This line starts with the number k satisfying 1 k 7, the number of rows, followed by k
positive integers l1, l2, . . . , lk. These integers specify the number of boxes on each row of the
Young diagram, and they satisfy 7 l1 l2 lk 1. The second line contains the
integer N, satisfying k N 7.
Output
For each test case, print one line containing the number of semi-standard Young tableaux
based on the given Young diagram, with the given N.
9
Problem D: Diagrams & Tableaux
Example
input output
1 1
1
1 1
2
2 2 1
4
4 3 2 1 1
4
1
2
20
20
10

题意:

给出一个那种形状,由很多个方格组成。每个方格中可以放1~N中的一个数,要求方格中的数大于上面相邻方格中的数,大于等于左边相邻方格的数。求有多少种放法。

给出k,表示有k行,然后给出各行的方格数。然后给出N。

题解:

状压DP。

因为一列要求下面大于上面,即不能等于,每种数字只能用一次,可以用状态的二进制位表示有无哪个数字,于是2^7=128,用0~127就能表示一列的所有状态。

然后状态转移,相邻两列转,枚举所有情况也就127^2。

然后一共最多7列,转转就得了。

注意结果大,用long long。

 

代码:

  1 //#pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<queue>
 12 using namespace std;
 13 #define ll long long
 14 #define usll unsigned ll
 15 #define mz(array) memset(array, 0, sizeof(array))
 16 #define mf1(array) memset(array, -1, sizeof(array))
 17 #define minf(array) memset(array, 0x3f, sizeof(array))
 18 #define REP(i,n) for(i=0;i<(n);i++)
 19 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
 20 #define RD(x) scanf("%d",&x)
 21 #define RD2(x,y) scanf("%d%d",&x,&y)
 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 23 #define WN(x) printf("%d\n",x);
 24 #define RE  freopen("D.in","r",stdin)
 25 #define WE  freopen("huzhi.txt","w",stdout)
 26 #define mp make_pair
 27 #define pb push_back
 28 #define pf push_front
 29 #define ppf pop_front
 30 #define ppb pop_back
 31 const double pi=acos(-1.0);
 32 const double eps=1e-10;
 33 
 34 int k,n;
 35 int a[11];
 36 
 37 //int cntt[133];
 38 int cnt(int st) {
 39     //if(cntt[st]!=-1)return cntt[st];
 40     int t=0,tt=st;
 41     while(tt) {
 42         if(tt&1)t++;
 43         tt>>=1;
 44     }
 45     //cntt[st]=t;
 46     return t;
 47 }
 48 
 49 //int okk[133][133];
 50 int ok(int j,int k) {
 51     //if(okk[j][k]!=-1)return okk[j][k];
 52     if(cnt(j)<cnt(k)) {
 53         //okk[j][k]=0;
 54         return 0;
 55     }
 56     int tk=k,tj=j,ck=0,cj=0;
 57     while(tk) {
 58         if(tk&1==1) {
 59             while(tj) {
 60                 if(tj&1==1) {
 61                     if(cj>ck) {
 62                         //okk[j][k]=0;
 63                         return 0;
 64                     }
 65                     cj++;
 66                     tj>>=1;
 67                     break;
 68                 }
 69                 cj++;
 70                 tj>>=1;
 71                 if(!tj)while(1);
 72             }
 73         }
 74         ck++;
 75         tk>>=1;
 76     }
 77     //okk[j][k]=1;
 78     return 1;
 79 }
 80 
 81 ll d[11][133];
 82 int c[11],mj;
 83 
 84 ll farm() {
 85     int i,j;
 86     int maxst=1<<n;
 87     //printf("maxst = %d\n",maxst);
 88     mz(d);
 89     FOR(k,0,maxst-1)
 90     if(cnt(k)==c[1])d[1][k]=1;
 91 
 92     FOR(i,2,mj) {
 93         FOR(j,0,maxst-1) {
 94             FOR(k,0,maxst-1) {
 95                 if(d[i-1][j]!=0 && cnt(k)==c[i] && cnt(j)==c[i-1] && ok(j,k)) {
 96                     d[i][k]+=d[i-1][j];
 97                     //printf("d[%d][%x]=%I64d , d[%d][%x]=%I64d\n",i-1,j,d[i-1][j] ,i,k,d[i][k]);
 98                 }
 99             }
100         }
101     }
102     ll re=0;
103     FOR(i,0,maxst-1)re+=d[mj][i];
104     return re;
105 }
106 
107 int main() {
108     int i,j;
109     //mf1(cntt);
110     //mf1(okk);
111     while(RD(k)!=EOF) {
112         mz(c);
113         FOR(i,1,k) {
114             RD(a[i]);
115             FOR(j,1,a[i])c[j]++;
116         }
117         mj=a[1];
118         RD(n);
119         printf("%I64d\n",farm());
120     }
121     return 0;
122 }
View Code

 

转载于:https://www.cnblogs.com/yuiffy/p/4017757.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值