首先一眼感受到这题特别的性质……5个?这么小的,感觉就像是状压。脑补了一下,如果没有环的话应该很好做吧……有环怎么办?5真的很小的,随便乱搞肯定也可以。那就放在外面暴力枚举吧。然后正解就出来了。
然而这题题面真的有毒吧。说好的不能全部选走?我还多加了一个维度,结果数据里面允许全部取走……然后对于<5的点单独写了个爆搜。代码奇长……大家看看就好吧(以及位运算本人一贯以来又清奇又暴力的脑回路……)
dp[][][0/1],1代表已经保留了至少一个动物……如果要A掉此题的话把转移那里加上dp[][][0]的就好了。整个namespace Speacial都是特判的点……(虽然数据里面并没有)
#include <bits/stdc++.h> using namespace std; #define CNST 32 #define maxn 10300 int n, c, tot, fans = 0, dp[maxn][CNST][2]; int num1[maxn * 5], num2[maxn * 5]; int lst[6] = {0, 1, 3, 7, 15, 31}; int fst[6] = {0, 16, 24, 28, 30, 31}; vector <int> V[maxn]; int read() { int x = 0; char c; c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x; } void gmax(int &a, int b) { a = a > b ? a : b; } void print(int x) { int a[15], tot = 0; a[5] = a[4] = a[3] = a[2] = a[1] = 0; while(x) { a[++ tot] = x & 1; x >>= 1; } for(int i = 5; i; i --) printf("%d", a[i]); return; } void work(int x, int sum, int opt) { int tem = 0; for(vector <int> :: iterator i = V[x].begin(); i < V[x].end(); i ++) { int k = *i; if((sum & num2[k]) || (num1[k] > (sum & num1[k]))) tem ++; } dp[x][sum][opt] += tem; int k1 = (sum << 1) & (fst[4]), k2 = (((sum << 1) & (fst[4])) | 1); gmax(dp[x + 1][k1][opt], dp[x][sum][opt]); gmax(dp[x + 1][k2][1], dp[x][sum][opt]); } int Check(int now, int sum) { int ans = 0; for(int i = 1; i <= 4; i ++) { int a = now, b = sum, t = 0; t = a & (lst[5 - i]); t <<= i; t |= ((b & (fst[i])) >> (5 - i)); for(vector <int> :: iterator j = V[i].begin(); j < V[i].end(); j ++) { int k = *j; if((t & num2[k]) || (num1[k] > (t & num1[k]))) ans ++; } } return ans; } int DP(int sum, int opt) { memset(dp, -1, sizeof(dp)); int ans = 0; dp[5][sum][opt] = 0; work(5, sum, opt); for(int i = 6; i <= n; i ++) { int maxx = 0; for(int j = 0; j < CNST; j ++) for(int k = 0; k <= 1; k ++) { if(~dp[i][j][k]) work(i, j, k); maxx = max(maxx, dp[i][j][k]); } } for(int j = 0; j < CNST; j ++) { if(dp[n][j][1] == -1) continue; int p = Check(j, sum); ans = max(ans, p + dp[n][j][1]); } return ans; } void dfs(int x, int sum) { if(x == 5) { sum <<= 1; if(sum & (CNST - 1)) fans = max(fans, DP(sum, 1)); else fans = max(fans, DP(sum, 0)); sum |= 1; fans = max(fans, DP(sum, 1)); return; } sum <<= 1; dfs(x + 1, sum); dfs(x + 1, sum |= 1); } int main() { n = read(), c = read(); for(int i = 1; i <= c; i ++) { int E = read(), F = read(), L = read(); int id = E + 4; if(id > n) id -= n; V[id].push_back(++ tot); for(int j = 1; j <= F; j ++) //害怕 { int x = read(); x = id - x; if(x < 0) x += n; num1[tot] |= (1 << x); } for(int j = 1; j <= L; j ++) //喜欢 { int x = read(); x = id - x; if(x < 0) x += n; num2[tot] |= (1 << x); } } dfs(1, 0); printf("%d ", fans); return 0; }