1. 程式人生 > >HNOI2017 大佬

HNOI2017 大佬

Link

Diffculty

演算法難度5,思維難度6,程式碼難度6

Description

由於題面過於複雜,這裡就不貼了,自己看連結吧。。。

Solution

首先我們可以dp求出可以自由支配的最大天數 d d ,直接 d p

( i , j ) dp(i,j) 代表第 i i
天,血量為 j j ,所能自由支配的最大天數。

然後我們考慮 b f s bfs 求出所有合法二元組 (

F , C ) (F,C) ,代表打出傷害 F F 最少需要 C C 天,這裡需要注意map判重,不然會掛的非常慘。

對於一個血量為 T T 的大佬,符合條件的兩個二元組一定滿足這兩個不等式:
F i + F j T , F i + F j + d C i C j 2 T F_i+F_j\le T,F_i+F_j+d-C_i-C_j-2\ge T
那麼我們將二元組按照 F i F_i 排序,令 F i F_i 遞減,那麼符合條件的 F j F_j 一定遞增,觀察後面的式子,發現我們只需要維護 F j C j F_j-C_j 的最大值即可,直接 t w o two p o i n t e r pointer 掃一下就好了。

時間複雜度真心玄學。。。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#define LL long long
using namespace std;
inline int read(){
	int x=0,f=1;char ch=' ';
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
	return f==1?x:-x;
}
typedef pair<int,int> pii;
const int N=105,M=1e7;
struct data{int F,L,C;};
int n,m,mc,d,cnt,a[N],w[N];
int dp[N][N];
queue<data> q;
map<pii,int> vis;
struct data2{
	int x,y;
	bool operator < (const data2& b) const {return x<b.x;}
}Q[M];
inline bool solve(int C){
	if(C<=d)return 1;
	int j=0,mx=-1e9;
	for(int i=cnt;i>=1;--i){
		if(Q[i].x<=C && d>Q[i].y && C-Q[i].x<=d-Q[i].y-1)return 1;
		while(j<cnt && Q[i].x+Q[j+1].x<=C){
			j++;
			mx=max(mx,Q[j].x-Q[j].y);
		}
		if(Q[i].x-Q[i].y+mx+d-2>=C)return 1;
	}
	return 0;
}
int main(){
	memset(dp,-1,sizeof dp);
	n=read();m=read();mc=read();
	for(int i=1;i<=n;++i)a[i]=read();
	for(int i=1;i<=n;++i)w[i]=read();
	dp[0][mc]=0;
	for(int i=0;i<n;++i){
		for(int j=0;j<=mc;++j){
			if(dp[i][j]<0)continue;
			int t=j-a[i+1];if(t<0)continue;
			dp[i+1][t]=max(dp[i+1][t],dp[i][j]+1);
			t=min(t+w[i+1],mc);
			dp[i+1][t]=max(dp[i+1][t],dp[i][j]);
		}
	}
	for(int i=1;i<=n;++i)for(int j=0;j<=mc;++j)d=max(d,dp[i][j]);
	q.push((data){1,0,0});
	while(!q.empty()){
		data x=q.front();
		q.pop();
		if(x.C>d-1)continue;
		else if(x.C==d-1){Q[++cnt]=(data2){x.F,x.C};continue;}
		else Q[++cnt]=(data2){x.F,x.C};
		if(x.L && (LL)x.F*x.L<=1e8 && !vis[pii(x.F*x.L,x.L)]){
			q.push((data){x.F*x.L,x.L,x.C+1});
		    vis[pii(x.F*x.L,x.L)]=x.C+1;
		}
		if(!vis[pii(x.F,x.L+1)]){
			q.push((data){x.F,x.L+1,x.C+1});
			vis[pii(x.F,x.L+1)]=x.C+1;
		}
	}
	sort(Q+1,Q+cnt+1);
	for(int s=1;s<=m;++s){
		int C=read();
	    if(solve(C))printf("1\n");
		else printf("0\n");
	}
	return 0;
}