2298: [HAOI2011]problem a
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 766 Solved: 346
[Submit][Status][Discuss]
Description
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Input
第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi
Output
一个整数,表示最少有几个人说谎
Sample Input
3
2 0
0 2
2 2
2 0
0 2
2 2
Sample Output
1
HINT
100%的数据满足: 1≤n≤100000 0≤ai、bi≤n
首先,要求最少说谎人数,即最大说真话人数。
对于每一个人,有a[i]个比他分数高的,b[i]个比他分数低的。则若序列为单调不增序列,和他同分的人的序号一定在a[i]+1->n-b[i]之间。因此可以想象成一段线段,问题转化为在一个长度为n的线段上有几段线段,求几段不想交的线段的长度之和,使这个值最大。
于是就是一个dp的题目了。方程显而易见。
又了解了一个map,在黄学长题解里还看到了动态数组?自己STL好弱……过几天系统学一下。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<map> using namespace std; map <pair<int,int>,int> s; int a,b,n,m,dp[100001],head[100001],next[100001],list[100001]; void add(int x,int y) { next[++m]=head[x]; head[x]=m; list[m]=y; } int main() { scanf("%d",&n); m=0; for (int i=1;i<=n;i++) { scanf("%d%d",&a,&b); if (a+b>=n) continue; a++; b=n-b; if (!s[make_pair(a,b)]) add(b,a); s[make_pair(a,b)]=min(s[make_pair(a,b)]+1,b-a+1); } for (int i=1;i<=n;i++) { dp[i]=dp[i-1]; for (int j=head[i];j;j=next[j]) { int u=list[j]-1; dp[i]=max(dp[i],dp[u]+s[make_pair(u+1,i)]); } } printf("%d",n-dp[n]); return 0; }