洛谷 P3724 大佬 —— 决策dp + BFS

题目链接:点我啊╭(╯^╰)╮

题目大意:

     中文题

解题思路:

    发现自己的自信值是否足够和能否打败大佬是两码事
    因此可以先用一个 DPDP 求出最多可以腾出多少天可以来蓄力,设最多有 DD
    然后接下来肯定是用一个 DPDP 求出最终答案,但是这个 DPDP 用什么来最为转移的数据完全不知道
    那么假设有一个 pair(d,f)pair:(d, f),表示用 dd 天,可以造成 ff 的攻击
    也就是说如果知道了所有的 pairpair,就可以进行 dpdp 了(虽然还不知道怎么 dpdp
    很明显,可以通过 BFSBFS 来求出所有 pairpair ,那么如何计算时间复杂度呢?
    可以猜测必须通过这些 pairpair 进行 dpdp ,那么这些 pairpair 的数量一定不会太大
    所以可以直接 BFSBFS 就完事了!注意要去重


    如果最多只能攻击一次,则只需满足 fcf ≤ c   &&\&\&   f+Ddcf + D - d ≥ c 即可
    如果能攻击两次,设对应的两个 pairpair(d1,f1)(d2,f2)(d1, f1) ,(d2, f2)
    f1+f2cf1 + f2 ≤ c   &&\&\&   f1+f2+(Dd1d2)cf1 + f2 + (D - d1 - d2) ≥ c
    暴力枚举肯定不行, 那么思考是否能满足决策优化
    对 ff 进行从小到大的排序,则随着 f1f1 的增大,f2f2 一直减少
    但如果这样枚举会产生不合法的 pairpair,只需要对 f1f1 从大到小枚举即可
    特别注意要特判单独的 f1f1 是否满足 以及 cDc ≤ D 的情况

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 105;
int n, m, mc, a[maxn], w[maxn], c[maxn]; 
int D, dp[maxn][maxn], mxc, top;
map <pii, int> mp;
struct node{
	int d, f, l;
	bool operator < (const node A) const {
		if(f == A.f) return d < A.d;
		return f < A.f;
	}
} st[2000005];

int getD(){
	for(int i=1; i<=n; i++)
		for(int j=a[i]; j<=mc; j++){
			dp[i][j-a[i]] = max(dp[i][j-a[i]], dp[i-1][j] + 1);
			int nj = min(mc, j - a[i] + w[i]);
			dp[i][nj] = max(dp[i][nj], dp[i-1][j]);
		}
	int ret = 0;
	for(int i=1; i<=n; i++) 
		for(int j=0; j<=mc; j++)
			ret = max(ret, dp[i][j]);
	return ret;
}

void bfs(){
	queue <node> q;
	node u = {1, 1, 0}, v;
	q.push(u);
	while(q.size()){
		u = q.front(), q.pop();
		if(u.d >= D) continue;
		q.push({u.d + 1, u.f, u.l + 1});
		if(u.l <= 1 || 1ll * u.f * u.l > 1ll * mxc) continue;
		if(mp[{u.d + 1, u.f * u.l}]) continue;
		v.d = u.d + 1, v.f = u.f * u.l, v.l = u.l;
		q.push(v), mp[{u.d + 1, u.f * u.l}] = 1;
		st[++top] = {u.d + 1, u.f * u.l};
	}
}

signed main() {
	scanf("%d%d%d", &n, &m, &mc);
	for(int i=1; i<=n; i++) scanf("%d", a+i);
	for(int i=1; i<=n; i++) scanf("%d", w+i);
	for(int i=1; i<=m; i++) scanf("%d", c+i), mxc = max(mxc, c[i]);
	D = getD();
	bfs();
	sort(st+1, st+1+top);
	for(int i=1; i<=m; i++){
		int f = 0, mx = -1e9;
		if(c[i] <= D) {
			printf("%d\n", 1);
			continue;
		}
		for(int f1=top, f2=1; f1; f1--){
			while(f2 < top && st[f1].f + st[f2].f <= c[i]) 
				mx = max(mx, st[f2].f - st[f2].d), f2++;
			if(st[f1].f+D-st[f1].d+mx >= c[i]) {
				f = 1;
				break;
			}
			if(st[f1].f<=c[i] && st[f1].f-st[f1].d+D >= c[i]) {
				f = 1;
				break;
			}
		}
		printf("%d\n", f);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章