題目大意:
有N只可愛的小海龜在賽跑。詢問每只小海龜它是第幾名,它會回答你兩個數,ai,bi,分別表示在它前面的小海龜數和在它后面的小海龜數。接著你發現其中有些小海龜對你撒了謊,因為根據他們的說法你根本沒法給他們排隊!但是你是善良的,你不希望有很多小海龜在撒謊,想找出最少有哪幾只小海龜在撒謊。(注意:小海龜的名次可能是并列的?。?/span>
分析:
若一只海龜說了真話,那么該海龜的位置一定是在區間[ai+1,n-bi] 上。若有k只海龜選擇了相同的區間 ,則根據并列關系,該區間最多能同時擁有min{n-ai-bi,k}只海龜(多出來的海龜肯定是說謊的,預先排除掉)。可以計算出每個區間最多能有多少只海龜,把數值看做區間的“權”。則問題轉化為,在一些帶權區間中,選出權和最大的區間,使它們之間不能互相重疊。
算法:
算出每個出現過的區間的“權”vi ,接下來的算法就是動態規劃了。先按右端點坐標從小到大排序,令pi 為在區間 i左邊的且與之無公共點的最大區間編號,設狀態f[i] 為在前i 個區間中可選出區間的最大權和,則狀態轉移方程為f(i)=max(f(i-1),f(pi)+vi) ,說真話海龜的最大數量就是最后一個區間的f(i) 值。
論文:/Files/yzhw/range.rar
注意,在區間類問題中,要合理設計狀態,究竟狀態表示的是前i個區間(第i個區間不一定取)還是第i個區間一定要取的前i個區間。
1
# include <iostream>
2
# include <map>
3
# include <vector>
4
# include <cstring>
5
# include <cstdio>
6
using namespace std;
7
vector<int> ans;
8
map<int,vector<int> > refer;
9
# define pos(a,b) (((b)<<10)|(a))
10
struct node
11

{
12
int s,e,val,per;
13
}ran[1001];
14
int dp[1001];
15
int path[1001];
16
bool used[1001];
17
int c=1;
18
int searchper(int pos)
19

{
20
int s=1,mid,e=c;
21
e--;
22
while(s<=e)
23
{
24
mid=(s+e)/2;
25
if(ran[mid].e>=pos)
26
e=mid-1;
27
else
28
s=mid+1;
29
}
30
return e;
31
}
32
int main()
33

{
34
int n;
35
scanf("%d",&n);
36
for(int i=0;i<n;i++)
37
{
38
int a,b;
39
scanf("%d%d",&a,&b);
40
if(a+b+1>n)
41
ans.push_back(i);
42
else
43
{
44
if(refer[pos(a+1,n-b)].size()<n-b-a)
45
refer[pos(a+1,n-b)].push_back(i);
46
else
47
ans.push_back(i);
48
}
49
}
50
for(map<int,vector<int> >::iterator i=refer.begin();i!=refer.end();i++)
51
{
52
ran[c].s=(i->first)&1023;
53
ran[c].e=((i->first)>>10);
54
ran[c++].val=(i->second).size();
55
}
56
for(int i=1;i<c;i++)
57
ran[i].per=searchper(ran[i].s);
58
dp[0]=0;
59
path[0]=-1;
60
for(int i=1;i<c;i++)
61
{
62
if(dp[i-1]>dp[ran[i].per]+ran[i].val)
63
path[i]=0,dp[i]=dp[i-1];
64
else
65
path[i]=1,dp[i]=dp[ran[i].per]+ran[i].val;
66
}
67
memset(used,false,sizeof(used));
68
int p=c-1;
69
while(p)
70
{
71
if(path[p])
72
{
73
used[p]=true;
74
p=ran[p].per;
75
}
76
else
77
p--;
78
}
79
for(int i=1;i<c;i++)
80
if(!used[i])
81
for(int j=0;j<refer[pos(ran[i].s,ran[i].e)].size();j++)
82
ans.push_back(refer[pos(ran[i].s,ran[i].e)][j]);
83
printf("%d",ans.size());
84
for(int i=0;i<ans.size();i++)
85
printf(" %d",ans[i]+1);
86
printf("\n");
87
return 0;
88
}
89
90