最近做了usaco2014 open的金组,果然美帝的题还是没有太简单啊QAQ,被每年的月赛骗了QAQ
不过话说官方题解真心棒(虽然英文的啃得好艰难,我英语渣你们别鄙视我= =),标程超级优美QAQ
按照标程打,学到了好多STL的用法= =(没办法,我c++底子弱)
这道题嘛,可以发现对于每个区间,只要左边界确定,可能的集合就一共只有8种了
考虑前缀和,发现若L~R为可行解,则对于所有种类的牛,有S[R]-S[L]=K或0
如何防止枚举K,可以发现在该集合中B的s[L][bi]减去s[L][b0]就行了
那么就hash,枚举集合B,求出hash值,直接做就行了
CODE:(直接贴标程了,Map真的用的是神出鬼没啊QAQ)
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <cstdio> #include <cassert> #include <map> using namespace std; #define MAXN 100010 #define GROUPS 8 int MB[MAXN][GROUPS]; int MF[MAXN][GROUPS]; int PS[MAXN][GROUPS]; int main() { freopen("fairphoto.in", "r", stdin); freopen("fairphoto.out", "w", stdout); int N, K; cin >> N >> K; vector<pair<int, int> > A(N); for(int i = 0; i < N; i++) { cin >> A[i].first >> A[i].second; A[i].second--; } sort(A.begin(), A.end()); /* Construct backstep masks */ for(int i = 0; i < GROUPS; i++) { MB[0][i] = 1 << A[0].second; } for(int i = 1; i < N; i++) { int bt = 1 << A[i].second; MB[i][0] = bt; for(int j = 1; j < GROUPS; j++) { if(MB[i - 1][j] & bt) { MB[i][j] = MB[i - 1][j]; } else { MB[i][j] = bt | MB[i - 1][j - 1]; } } } /* Construct forward step masks */ for(int i = 0; i < GROUPS; i++) { MF[N - 1][i] = 1 << A[N - 1].second; } for(int i = N - 2; i >= 0; i--) { int bt = 1 << A[i].second; MF[i][0] = bt; for(int j = 1; j < GROUPS; j++) { if(MF[i + 1][j] & bt) { MF[i][j] = MF[i + 1][j]; } else { MF[i][j] = bt | MF[i + 1][j - 1]; } } } /* Construct partial sums */ for(int i = 0; i < N; i++) { memcpy(PS[i + 1], PS[i], sizeof(PS[i])); ++PS[i + 1][A[i].second]; } int result = -1; for(int j = K - 1; j < GROUPS; j++) { vector<int> V(1 + GROUPS); map<vector<int>, int> cost_map; /* Compute the earliest starts for given masks * and normalized partial sums. */ for(int i = N - 1; i >= 0; i--) { int base = -1; int m = V[GROUPS] = MF[i][j]; if(__builtin_popcount(m) <= j) continue; for(int k = 0; k < GROUPS; k++) { if(m & 1 << k) { if(base == -1) { base = PS[i][k]; } V[k] = PS[i][k] - base; } else { V[k] = PS[i][k]; } } cost_map[V] = A[i].first; } /* Find best start points for each ending position. */ for(int i = 0; i < N; i++) { int base = -1; int m = V[GROUPS] = MB[i][j]; if(__builtin_popcount(m) <= j) continue; for(int k = 0; k < GROUPS; k++) { if(m & 1 << k) { if(base == -1) { base = PS[i + 1][k]; } V[k] = PS[i + 1][k] - base; } else { V[k] = PS[i + 1][k]; } } map<vector<int>, int>::iterator it = cost_map.find(V); if(it != cost_map.end() && it->second < A[i].first) { result = max(result, A[i].first - it->second); } } } cout << result << endl; return 0; }