HNOI2017 大佬
阿新 • • 發佈:2018-12-13
Link
Diffculty
演算法難度5,思維難度6,程式碼難度6
Description
由於題面過於複雜,這裡就不貼了,自己看連結吧。。。
Solution
首先我們可以dp求出可以自由支配的最大天數
,直接
代表第
天,血量為
,所能自由支配的最大天數。
然後我們考慮 求出所有合法二元組 ,代表打出傷害 最少需要 天,這裡需要注意map判重,不然會掛的非常慘。
對於一個血量為
的大佬,符合條件的兩個二元組一定滿足這兩個不等式:
那麼我們將二元組按照
排序,令
遞減,那麼符合條件的
一定遞增,觀察後面的式子,發現我們只需要維護
的最大值即可,直接
掃一下就好了。
時間複雜度真心玄學。。。
#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;
}