您的位置:首页 > 其它

2018.10.17校内模拟赛:T2神光

2018-10-17 16:54 525 查看

题面: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次红光的时候,最少的绿光次数。

 

代码:

/*
* @Author: mjt
* @Date:   2018-10-17 16:16:28
* @Last Modified by:   mjt
* @Last Modified time: 2018-10-17 16:40:30
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL;

inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 2005;

int a
, P
, Q
, f

, n, R, G;

bool check(int x) {
memset(f, 0, sizeof(f));
memset(P, 0, sizeof(P));
memset(Q, 0, sizeof(Q));
for (int i=1; i<=n; ++i) {
for (int j=i; j<=n; ++j) {
if (a[j] - a[i] + 1 <= x) P[i] = j;
if (a[j] - a[i] + 1 <= x + x) Q[i] = j;
}
}
P[n + 1] = Q[n + 1] = n;
for (int i=0; i<=R; ++i)
for (int j=0; j<=G; ++j) {
if (i) f[i][j] = max(f[i][j], P[f[i - 1][j] + 1]);
if (j) f[i][j] = max(f[i][j], Q[f[i][j - 1] + 1]);
}
return f[R][G] == n;
}

int main() {
n = read(), R = read(), G = read();
for (int i=1; i<=n; ++i) a[i] = read();
sort(a + 1, a + n + 1);
if (R + G >= n) {
cout << 1; return 0;
}
int L = 1, R = a
 - a[1] + 1, ans = R;
while (L <= R) {
int mid = (L + R) >> 1;
if (check(mid)) ans = mid, R = mid - 1;
else L = mid + 1;
}
cout << ans;
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: