【校内模拟】王强的疑惑

团队题目链接

王强的疑惑(\(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;
}
posted @ 2018-11-05 17:09  yjk  阅读(147)  评论(0编辑  收藏  举报