P3724 [AHOI2017/HNOI2017] 大佬 做题记录
P3724 [AHOI2017/HNOI2017] 大佬
Description
https://www.luogu.com.cn/problem/P3724
Solution
回血和怼大佬没有关系,所以我们将其拆开考虑。
先考虑回血。我们可以先求出自己最多能活着怼大佬多少天。这部分可以用平凡的 dp 求解,并设最大天数为 \(D\)。
再考虑怼大佬。技能最多发动两次,我们可以以此为切入点。
对于一个 $F $,我们肯定希望达成它的天数越少越好,以便有更多的时间继续进攻。
我们把所有 \(\leq C_i\) 的且能到达的 \(F_j\) 拿出来,并求出达到每个 \(F_j\) 的最小天数 \(D_j\)。
由于 \(F_j\leq 10^8\) 且只含 \(\leq 100\) 的因子,所以 \(F_j\) 的个数不会太多。打表发现只有 \(924572\) 个,约为 \(10^6\)。
考虑一个 BFS 的框架,以 \((F,L)\) 为状态求最短路。当 \(F\times L>10^8\) 时不能再拓展,且 \(L\leq 100\),打表发现可拓展的状态只有 \(15039235\) 个,约为 \(2\times 10^7\)。
对于大佬 \(C_i\),分为三种情况:
- \(D\geq C_i\),可以全用平 A;
- \(\exists j,F_j\leq C_j\land F_j+D-D_j\geq C_j\),可以发动一次技能,然后平 A;
- \(\exists j,k,F_j+F_k\leq C_i\land F_j+F_k+D-D_j-D_k\geq C_i\),可以发动两次技能,然后平 A。
重点考虑第三种情况。将所有的 \((F_j,D_j)\) 按 \(F_j\) 排序。从左向右枚举 \(j\),此时最大的 \(k\) 也是单调不降的。于是我们再维护一个 \(pre_k\) 表示 \(F_p-D_p\) 在 \([1,k]\) 之间的前缀最大值即可。
int n,m,k;
int a[N],b[N],c[N];
int f[N][N];
int D=-IINF;
const int mod=1000003;
struct HashTable{
int head[mod+5],tot;
struct HashNode{
int x,y,nxt;
}e[M];
void Init(){
memset(head,0,sizeof(head));
tot=0;
}
int GetHash(int x,int y){
return (1ll*x*10000%mod+y)%mod;
}
bool Find(int x,int y){
int v=GetHash(x,y);
for(int i=head[v];i;i=e[i].nxt){
if(e[i].x==x&&e[i].y==y)
return 1;
}
return 0;
}
void Ins(int x,int y){
int v=GetHash(x,y);
e[++tot]={x,y,head[v]};
head[v]=tot;
}
}H;
struct BfsNode{
int x,y,d;
};
queue<BfsNode> q;
bitset<K> vis;
int tg,h[M];
struct FNode{
int f,d;
}g[M];
bool Cmp(FNode x,FNode y){return x.f<y.f;}
void Bfs(int C){
H.Init();
H.Ins(1,0);
q.push({1,0,0});
vis.set(0);
tg=0;
while(q.size()){
int x=q.front().x,y=q.front().y,d=q.front().d;
q.pop();
if(d>=D) continue;
if(!vis[x]){
g[++tg]={x,d+1};
vis[x]=1;
}
if(!H.Find(x,y+1)){
q.push({x,y+1,d+1});
H.Ins(x,y+1);
}
if(1ll*x*y<=C&&!H.Find(x*y,y)){
q.push({x*y,y,d+1});
H.Ins(x*y,y);
}
}
}
signed main(){
read(n),read(m),read(k);
int Mx=0;
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) read(b[i]);
for(int i=1;i<=m;i++) read(c[i]),Ckmax(Mx,c[i]);
memset(f,-0x3f,sizeof(f));
f[0][k]=0;
for(int i=1;i<=n;i++){
for(int j=a[i];j<=k;j++){
Ckmax(f[i][j-a[i]],f[i-1][j]+1);
int v=min(k,j-a[i]+b[i]);
Ckmax(f[i][v],f[i-1][j]);
}
for(int j=0;j<=k;j++) Ckmax(D,f[i][j]);
}
if(D<=0){
for(int i=1;i<=m;i++) puts("0");
return 0;
}
Bfs(Mx);
sort(g+1,g+tg+1,Cmp);
h[0]=-IINF;
for(int i=1;i<=tg;i++){
h[i]=max(h[i-1],g[i].f-g[i].d);
}
for(int i=1;i<=m;i++){
if(D>=c[i]){
puts("1");
continue;
}
bool ok=0;
for(int j=1,p=tg;j<=tg;j++){
if(g[j].f>c[i]) break;
// printf("J=%d\n",j);
if(g[j].f+D-g[j].d>=c[i]){ok=1;break;}
while(p>=1&&g[j].f+g[p].f>c[i]) p--;
if(p&&g[j].f+D-g[j].d+h[p]>=c[i]){ok=1;break;}
}
printf("%d\n",ok);
}
return 0;
}

浙公网安备 33010602011771号