2018.10.17校内模拟赛:T2神光

题面:pdf

首先排序,二分,然后怎么判定是否可行。

最简单的思路是,dp[i][j][k],到第i个,用了j次红光,k次绿光,前i个点都选上了,是否可行。然后转移就行。

然后考试的时候就想到这了,往后没想到。于是贪心,乱搞,和n^3dp拍了几千组随机数据。然后,一共90。其中贪心可得80。

上面的dp中,结果只能是0/1,于是可以考虑减掉一维,让结果表示一维。

n^2 dp:感觉挺奇妙的。f[i][j]红的用了i次,绿的用了j次,最远到什么位置。dp[i][j]=max ( P[dp[i-1][j]+1], Q[dp[i][j-1]+1] )。其中 P[k]表示使用一次红光,能从第 k 座法坛向右(正向为右)连续摧毁到第几座,Q[k]表示使用一次绿光,能从第k座法坛向右连续摧毁到第几座。 P和Q数组可以通过预处理得到。

其他的思路:f[i][j]到i,用了j次红光的时候,最少的绿光次数。

代码:

 1 /*
 2 * @Author: mjt
 3 * @Date:   2018-10-17 16:16:28
 4 * @Last Modified by:   mjt
 5 * @Last Modified time: 2018-10-17 16:40:30
 6 */
 7 #include<cstdio>
 8 #include<algorithm>
 9 #include<cstring>
10 #include<cmath>
11 #include<iostream>
12 #include<cctype>
13 #include<set>
14 #include<vector>
15 #include<queue>
16 #include<map>
17 #define fi(s) freopen(s,"r",stdin);
18 #define fo(s) freopen(s,"w",stdout);
19 using namespace std;
20 typedef long long LL;
21 
22 inline int read() {
23     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
24     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
25 }
26 
27 const int N = 2005;
28 
29 int a[N], P[N], Q[N], f[N][N], n, R, G;
30 
31 bool check(int x) {
32     memset(f, 0, sizeof(f));
33     memset(P, 0, sizeof(P));
34     memset(Q, 0, sizeof(Q));
35     for (int i=1; i<=n; ++i) {
36         for (int j=i; j<=n; ++j) {
37             if (a[j] - a[i] + 1 <= x) P[i] = j;
38             if (a[j] - a[i] + 1 <= x + x) Q[i] = j;
39         }
40     }
41     P[n + 1] = Q[n + 1] = n;
42     for (int i=0; i<=R; ++i)
43         for (int j=0; j<=G; ++j) {
44             if (i) f[i][j] = max(f[i][j], P[f[i - 1][j] + 1]);
45             if (j) f[i][j] = max(f[i][j], Q[f[i][j - 1] + 1]);
46         }
47     return f[R][G] == n;
48 }
49 
50 int main() {
51     n = read(), R = read(), G = read();
52     for (int i=1; i<=n; ++i) a[i] = read();
53     sort(a + 1, a + n + 1);
54     if (R + G >= n) {
55         cout << 1; return 0;
56     }
57     int L = 1, R = a[n] - a[1] + 1, ans = R;
58     while (L <= R) {
59         int mid = (L + R) >> 1;
60         if (check(mid)) ans = mid, R = mid - 1;
61         else L = mid + 1;
62     }
63     cout << ans;
64     return 0;
65 }
原文地址:https://www.cnblogs.com/mjtcn/p/9805212.html