HNOI2017 大佬

Link

Diffculty

算法难度5,思维难度6,代码难度6

Description

由于题面过于复杂,这里就不贴了,自己看链接吧。。。

Solution

首先我们可以dp求出可以自由支配的最大天数 d d d,直接 d p ( i , j ) dp(i,j) dp(i,j)代表第 i i i天,血量为 j j j,所能自由支配的最大天数。

然后我们考虑 b f s bfs bfs求出所有合法二元组 ( F , C ) (F,C) (F,C),代表打出伤害 F F F最少需要 C C C天,这里需要注意map判重,不然会挂的非常惨。

对于一个血量为 T 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 Fi+FjT,Fi+Fj+dCiCj2T
那么我们将二元组按照 F i F_i Fi排序,令 F i F_i Fi递减,那么符合条件的 F j F_j Fj一定递增,观察后面的式子,发现我们只需要维护 F j − C j F_j-C_j FjCj的最大值即可,直接 t w o two two p o i n t e r pointer pointer扫一下就好了。

时间复杂度真心玄学。。。

#include
#include
#include
#include
#include
#include
#include
#include
#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;
}

你可能感兴趣的:(HNOI2017 大佬)