【校内模拟】王强的疑惑
团队题目链接
王强的疑惑(\(math\))
时限:\(2s\) 空间:\(256MB\)
【题目背景】
在遥远的\(\mathcal{DeepDark}\)星系中,生活着一种神奇的生物——王\(♂\)强,他们鳝长于\(AK\) \(OI\) 比赛,在一个\(\mathcal{van}\)物复苏的季节,一只年轻的雄性王强开始了他的\(AK\)活动...
【题目描述】
\(\mathcal{DeepDark}\)星系中有\(n\)个星球在举行\(OI\)比赛,星球的名称分别是\(1\)号星球,\(2\)号星球……,\(n\)号星球,第\(i\)个星球的全球决赛叫做\(IOI\),由于每个星球的自转和公转时间不同,所以他们\(OI\)赛的时间也不同;
现在王\(♂\)强知道了每一场\(OI\)赛的开始时间\(a_i\)和结束时间\(b_i\),并且根据他往年\(AK\)的次数,预测了每个\(OI\)赛他\(AK\)的概率\(p_i\);
每个星球只有\(1\)场比赛,王\(♂\)强不能在同一时刻在两个星球上;
王\(♂\)强一开始在\(1\)号星球上,而他从任意一个星球移动另一个星球需要\(q\)的时间;
现在王\(♂\)强想知道他该如何参加比赛,使他的期望\(AK\)场数最大。
【输入输出格式】
输入格式
第1行两个整数\(n\)和\(q\);
接下来\(n\)行,第\(i+1\)行有两个整数和一个小数,
分别表示\(TOI\)的开始时间\(a_i\),结束时间\(b_i\)和王\(♂\)强\(AK\)\(IOI\)的概率\(p_i\)
输出格式
第1行一个浮点数,表示王\(♂\)强最大期望能够\(AK\)的场数,保留三位小数
第2行输出王\(♂\)强\(AK\)的星球编号,中间用空格隔开,数据保证只有一组解
【输入样例】
输入样例#1:
5 2
7 10 0.8123456789
2 5 0.223456789
6 9 0.83456789
3 6 0.3456789
8 10 0.756789
输入样例#2:
14 0
2 7 0.37
0 1 0.20
8 9 0.13
1 5 0.19
0 8 0.4
0 2 0.57
0 3 0.2
4 9 0.4
5 9 0.26
8 10 0.80
9 10 0.27
3 7 0.3
5 9 0.64
3 9 0.55
【输出样例】
输出样例#1:
1.102
4 5
输出样例#2:
1.740
6 1 10
【数据范围】
对于\(100\%\)的数据,\(1\leq n\leq 10^6,0\leq l_i< r_i\leq 10^6,0\leq p_i\leq 1,0\leq q\leq10^5\)
特殊限制:
测试点 | \(n\) | \(q,p_i\) | 分值 |
---|---|---|---|
1 | \(\leq 15\) | — | \(15\) |
2 | \(\leq 15\) | — | \(15\) |
3 | \(\leq 1000\) | \(q=1,p_i=0\) | \(15\) |
4 | \(\leq 1000\) | — | \(15\) |
5 | \(\leq 10^6\) | — | \(20\) |
6 | \(\leq 10^6\) | — | \(20\) |
【题解】
显然这是一道递归\(DP\)题,
\(dp_i\)表示时间为\(i\)时的最大期望收益
考虑当区间\(j\)的右端点\(c_j.r\)等于\(i\)时,我们可以进行转移
\(dp[i] = \max ( dp[c_j . l] + c_j.w )\)
我们可以将所有区间按照右端点排个序,然后枚举时间\(i\),进行\(dp\),
有一个细节是王♂强一开始在\(1\)号星球,在转移的时候特判一下即可
if(c[j].id==1){
if(dp[i]<c[j].w) dp[i]=c[j].w;
//...
}
显然每个\(i\)会被枚举到一次,每个区间会用到一次
\(DP\)的复杂度是\(O(n+maxr)\)的
但是\(sort\)是\(O(nlogn)\)的
所以总的复杂度为\(O(nlogn)\)
\(\mathcal{std}\)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1000010
int n,p,pre[N],ans[N],stack[N],top;
struct _OI{
int l,r,id;
double w;
} c[N];
double f[N];
bool cmp(_OI x,_OI y){
return x.r<y.r;
}
int main()
{
scanf("%d%d",&n,&p);
int maxr=0;
for(int i=1;i<=n;i++){
scanf("%d%d%lf",&c[i].l,&c[i].r,&c[i].w);
maxr=max(maxr,c[i].r);
c[i].id=i;
}
sort(c+1,c+1+n,cmp);
int j=1;
for(int i=1;i<=maxr;i++){
f[i]=f[i-1]; pre[i]=i-1;
while(c[j].r==i){
if(c[j].l>=p&&f[i]<f[c[j].l-p]+c[j].w){
f[i]=f[c[j].l-p]+c[j].w;
pre[i]=c[j].l-p;
ans[i]=j;
}
if(c[j].id==1&&f[i]<c[j].w){
f[i]=c[j].w;
pre[i]=0;
ans[i]=j;
}
++j;
}
}
printf("%.3lf\n",f[maxr]);
int now=maxr;
while(!ans[now]&&now) --now;
while(now){
if(ans[now]) stack[++top]=c[ans[now]].id;
now=pre[now];
}
while(top){
printf("%d ",stack[top]);
--top;
}
return 0;
}