传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2298
这道题真是纠结。。。
通过补集思想,我们可以求最多说真话的人数,答案即为n-ans
又假设每个人都说了真话,则我们可以通过ai,bi来得出第i个人所在区间[l,r]
这里就有些纠结了,我开始想的是将这些区间按左端点排序,然后贪心的放人进去,发现这样是错的,那么就改成dp
设f[i]表示名次为1~i的最多有多少人,则f[i] = max(f[j - 1], sum[j, i]), sum[i][j]为区间为[i,j]的人数。
然后再搞一搞就行了。
#include <iostream> #include <cstdio> #include <cstring> #include <map> #include <vector> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 100010; map < pair <int, int> , int > s; vector <int> p[maxn]; int f[maxn]; int n; int main() { scanf("%d", &n); int a, b; for(int i = 1; i <= n; i ++) { scanf("%d%d", &a, &b); int t1 = a + 1, t2 = n - b; if(t1 > t2) continue; s[make_pair(t1, t2)] ++; if(s[make_pair(t1, t2)] == 1) p[t2].push_back(t1); } for(int i = 1; i <= n; i ++) { f[i] = f[i - 1]; int len = p[i].size(); for(int j = 0; j < len; j ++) { f[i] = max(f[i], f[p[i][j] - 1] + min(s[make_pair(p[i][j], i)], i - p[i][j] + 1)); } } printf("%d\n", n - f[n]); return 0; }