题意:给定一个n个元素的圈,m个条件。满足一个条件需要选某些元素或不选另一些元素。
问最多能满足多少条件。每个条件所关联的元素,最远的两个距离不会超过5。
解:想了半天......
首先能想到断环成链DP。
然后某个时刻灵光一闪,突然发现可以状压最近的5个位置......这样枚举开始位置做32次DP就行了!
实现的时候发现只要枚举16种开始情况,状压4个位置...
转移就是考虑下一个位置选/不选。
注意细节......为什么有人20行A题,我写了160行呀...
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 6 const int N = 10010; 7 8 struct Node { 9 int p, fear, like; 10 int a[5]; // 0 none 1 fear 2 like 11 }node[5 * N]; 12 13 int f[N][16], n; 14 std::vector<int> v[N]; 15 16 inline void exmax(int &a, int b) { 17 a < b ? a = b : 0; 18 return; 19 } 20 21 inline void out(int x, int tag) { 22 printf(" "); 23 for(int i = 0; i < tag; i++) { 24 printf("%d", (x >> i) & 1); 25 } 26 printf(" "); 27 return; 28 } 29 30 inline int check(Node x, int s) { 31 for(int i = 0; i < 5; i++) { 32 if(x.a[i] == 1 && ((s >> i) & 1)) { 33 return 1; 34 } 35 if(x.a[i] == 2 && (((s >> i) & 1) == 0)) { 36 return 1; 37 } 38 } 39 return 0; 40 } 41 42 int main() { 43 44 int m; 45 scanf("%d%d", &n, &m); 46 for(int i = 1, x; i <= m; i++) { 47 scanf("%d%d%d", &node[i].p, &node[i].fear, &node[i].like); 48 node[i].p += 4; 49 while(node[i].p > n) { 50 node[i].p -= n; 51 } 52 for(int j = 1; j <= node[i].fear; j++) { 53 scanf("%d", &x); 54 for(int k = 4, now = node[i].p + 1; k >= 0; k--) { 55 now--; 56 if(!now) { 57 now = n; 58 } 59 if(now == x) { 60 node[i].a[k] = 1; 61 break; 62 } 63 } 64 } 65 for(int j = 1; j <= node[i].like; j++) { 66 scanf("%d", &x); 67 for(int k = 4, now = node[i].p + 1; k >= 0; k--) { 68 now--; 69 if(!now) { 70 now = n; 71 } 72 if(now == x) { 73 node[i].a[k] = 2; 74 break; 75 } 76 } 77 } 78 v[node[i].p].push_back(i); 79 } 80 /// input 81 int ans = 0; 82 /// ----- 83 /// 01234 84 for(int op = 0; op < 16; op++) { /// first four 85 memset(f, 0, sizeof(f)); 86 for(int s = 0; s < 16; s++) { 87 if(s != op) { 88 f[4][s] = -1; 89 } 90 } 91 92 for(int i = 4; i < n; i++) { 93 for(int s = 0; s < 16; s++) { 94 if(f[i][s] == -1) { 95 continue; 96 } 97 /// f[i][s] -> f[i + 1][t] 98 99 int t = s >> 1, temp = f[i][s]; /// put 0 don't move 100 for(int j = 0; j < v[i + 1].size(); j++) { 101 /// node[v[i + 1][j]] and s 102 temp += check(node[v[i + 1][j]], s); 103 } 104 exmax(f[i + 1][t], temp); 105 // ------------------------------------- 106 t = t | (1 << 3); /// put 1 move 107 temp = f[i][s]; 108 for(int j = 0; j < v[i + 1].size(); j++) { 109 temp += check(node[v[i + 1][j]], s | (1 << 4)); 110 } 111 exmax(f[i + 1][t], temp); 112 } 113 } 114 for(int s = 0; s < 16; s++) { 115 /// f[n][s] 116 int temp = f[n][s], now = s << 1; 117 for(int i = 0; i < 4; i++) { 118 now = (now >> 1) + (((op >> i) & 1) << 4); 119 for(int j = 0; j < v[i + 1].size(); j++) { 120 temp += check(node[v[i + 1][j]], now); 121 } 122 } 123 exmax(ans, temp); 124 } 125 } 126 printf("%d\n", ans); 127 return 0; 128 }