洛谷 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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章