题目链接:BZOJ 2298
这道题,我一开始想的居然是2 - SAT。。。被否决后想一想发现,对于每个人的可能的排名为一个区间,然后我尝试着将区间作为权值来看,说谎的人数就是总人数减去可选的不相交的区间权值和,然后我就不知道怎么统计答案了QAQ。
我们可以用dp[i]表示到i节点,选的区间的权值和,转移dp[i] = max(dp[i], dp[j - 1] + i - j)。我们对于每一个节点,存一个以它结尾的区间的左端点,直接转移即可。STL大法好。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int maxn = 100000 + 10;
int N;
int dp[maxn];
map<pair<int, int>, int> num;
vector<int> q[maxn];
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
void input(){
N = read();
for(int i = 1; i <= N; ++i){
int x = read(), y = read();
int L = y + 1, R = N - x;
if(L <= R){
num[make_pair(L, R)] ++;
if(num[make_pair(L, R)] == 1)q[R].push_back(L);
}
}
}
void solve(){
for(int i = 1; i <= N; ++i){
dp[i] = dp[i - 1];
for(int j = 0; j < q[i].size(); ++j){
dp[i] = max(dp[i], dp[q[i][j] - 1] + min(i - q[i][j] + 1, num[make_pair(q[i][j], i)]));
}
}
cout << N - dp[N] << endl;
}
int main(){
input();
solve();
return 0;
}
本文介绍了一种解决BZOJ2298问题的有效算法,通过动态规划来确定最少的说谎者数量。利用区间权值的概念,以每个人可能的排名区间为基础,实现了高效的状态转移。
826

被折叠的 条评论
为什么被折叠?



