[SCOI2005]互不侵犯

嘟嘟嘟

 

做完[NOI2001]炮兵阵地这道题,顿时觉得此题好水~~15分钟AC

令dp[i][j][k]表示到第 i 行放了 j 个国王,该行状态为 k 时的方案数。然后dp的时候第一层循环枚举 i,第二层 j,如果j 合法的话,再枚举第三层 i - 1行的状态 k,然后如果k合法且 j 和k不冲突的话,再枚举国王数量h,于是就有:

    dp[i][h][j] += dp[i - 1][h - sum[j]][k]

至于如何判断j和k不冲突,那自然是 j & k == 0 且 j | k状态是合法的。

优化就是先预处理所有合法的 j 和k。

然后别忘了dp[1]单独处理。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a) memset(a, 0, sizeof(a))
15 typedef long long ll;
16 typedef double db;
17 const int INF = 0x3f3f3f3f;
18 const db eps = 1e-8;
19 const int max_sta = 100;        //经测试。合法的状态最多只有89种 
20 inline ll read()
21 {
22     ll ans = 0;
23     char ch = getchar(), last = ' ';
24     while(!isdigit(ch)) {last = ch; ch = getchar();}
25     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
26     if(last == '-') ans = -ans;
27     return ans;
28 }
29 inline void write(ll x)
30 {
31     if(x < 0) x = -x, putchar('-');
32     if(x >= 10) write(x / 10);
33     putchar(x % 10 + '0');
34 }
35 
36 int n, m;
37 int sum[max_sta], s[max_sta], cnt = 0;
38 bool ok[1000];
39 ll dp[10][100][max_sta];
40 
41 int getsum(int x)
42 {
43     int ret = 0;
44     for(; x; x >>= 1) ret += x & 1;
45     return ret;
46 }
47 void init()
48 {
49     for(int i = 0; i < (1 << n); ++i)
50         if(!(i & (i << 1)) && !(i & (i >> 1)))
51         {
52             s[++cnt] = i;
53             ok[i] = 1;
54             sum[cnt] = getsum(i);    
55             dp[1][sum[cnt]][cnt]++;
56         }
57 }
58 
59 int main()
60 {
61     n = read(); m = read();
62     init();
63     for(int i = 2; i <= n; ++i)
64         for(int j = 1; j <= cnt; ++j) 
65             for(int k = 1; k <= cnt; ++k) 
66                 if(!(s[j] & s[k]) && ok[s[j] | s[k]])
67                     for(int h = sum[j]; h <= m; ++h)
68                         dp[i][h][j] += dp[i - 1][h - sum[j]][k];
69     ll ans = 0;
70     for(int i = 1; i <= cnt; ++i) ans += dp[n][m][i];
71     write(ans); enter;
72     return 0;
73 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9622197.html