传送门: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;
}