11.12模拟题 by hzwer

T1:小奇挖矿 2(mining):

【题目背景】
小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光
之源的矿石交易市场,以便为飞船升级无限非概率引擎。

【问题描述】
现在有 m+1个星球,从左到右标号为 0到m,小奇最初在0号星球。
有n 处矿体,第i 处矿体有ai单位原矿,在第 bi个星球上。 //attention:矿石可能在同一个星球上--so w[b]+=a not w[b]=a--因为这个少了30分
由于飞船使用的是老式的跳跃引擎,每次它只能从第 x 号星球移动到第 x+4
号星球或x+7号星球。每到一个星球,小奇会采走该星球上所有的原矿,求小奇
能采到的最大原矿数量。
注意,小奇不必最终到达 m号星球。

【输入格式】
第一行2个整数n,m。
接下来n行,每行2个整数 ai,bi。

【输出格式】
输出一行一个整数,表示要求的结果。

【样例输入】
3 13
100 4
10 7
1 11

【样例输出】
101

【样例解释】
第一次从0到4,第二次从 4到11,总共采到 101单位原矿。

【数据范围】
对于20%的数据 n=1,m<=10^5
对于40%的数据 n<=15,m<=10^5
对于60%的数据 m<=10^5
对于100%的数据 n<=10^5,m<=10^9,1<=ai<=10^4,1<=bi<=m

题解:


小奇挖矿 2

1.对于 20%的数据,n=1。只需判断这个星球位置是否能拆分成 4和7 的和。
可以简单递推,枚举求得。
打表的话可以发现,只有 1 2 3 5 6 9 10 13 17 不能拆。

2.对于 40%的数据,n 很小。可以 2^n 枚举去哪些星球,然后用上面的方法判
定一个星球能否到下一个星球。

3.对于 60%的数据,m比较小。设 x[i]为i号星球的原矿数,f[i]为到 i号星
球能获得的最大原矿数,则 f[i]=max{f[i-4],f[i-7]}+x[i]。 //自己的思想

4.对于 100%的数据,m很大。
a.将所有矿物排序,f[i]为到第 i 个矿体能获得的最大原矿数,那么
f[i]=max{f[j]}+x[i],其中,i-j满足能拆分成 4和7。
这样 dp需要n^2 的复杂度,但是我们发现,相距超过 17的一定可达,那么
不超过17的范围内暴力,超过 17的取个最大值即可,复杂度 O(n)
b.可以把相邻的星球距离超过 17的压缩成 18,按照60%的做法dp

代码:

 1 #include<map>
 2 #include<set>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<iostream>
 8 #define inf 1000000000
 9 #define ll long long
10 using namespace std;
11 ll read()
12 {
13     ll x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 struct data{
19     int a,b;
20     friend bool operator<(data a,data b){
21         return a.a<b.a;//结构体重载运算符
22     }
23 }a[100005];
24 int n,m;
25 int v[2000005],f[2000005];
26 int main()
27 {
28     freopen("mining.in","r",stdin);
29     freopen("mining.out","w",stdout);
30     memset(f,-1,sizeof(f));
31     n=read();m=read();
32     for(int i=1;i<=n;i++)
33         a[i].b=read(),a[i].a=read();
34     sort(a+1,a+n+1);
35     int now=0;
36     for(int i=1;i<=n;i++)
37     {
38         if(a[i].a-a[i-1].a>17)now+=18,v[now]+=a[i].b;
39         else now+=a[i].a-a[i-1].a,v[now]+=a[i].b;
40     }
41     int ans=0;
42     f[0]=0;
43     for(int i=0;i<=now;i++)
44         if(f[i]!=-1)
45         {
46             f[i+4]=max(f[i+4],f[i]+v[i+4]);
47             f[i+7]=max(f[i+7],f[i]+v[i+7]);
48             ans=max(ans,f[now]);
49         }
50     printf("%d\n",ans);
51     return 0;
52 }

所获:

不得不说,信奥也还是要有数感。对于数字4 7得有感觉,两个质数、两个奇数等等对于后面代码和算法的优化极其重要,不然真的会无从下手。

比如这题,判断这个星球位置是否能拆分成 4和7 的和,发现,只有 1 2 3 5 6 9 10 13 17 不能拆,相距超过 17的一定可达,那么
不超过17的范围内暴力,超过 17的取个最大值即可。 这一点就是解题的关键

但总体来说,这是一道DP题目,有点类似与硬币问题。

猜你喜欢

转载自www.cnblogs.com/becase/p/11842140.html