利用不等式解题,搜索剪枝
SOL:
首先可以发现保证自己不死和怼大佬是可以分开的
一个(n^2DP)算出最多可以用来怼大佬的天数,问题就转化为用(n)天怼大佬是否成功
先求出所有可能的讽刺值及其天数,惊人发现竟存的下!看来要多尝试才好
这样攻击一次和零次的都可以轻易判断
攻击两次(讽刺值(f1,f2)天数(d1,d2)):
(f1+f2<=C,n-d1-d2>=C-f1-f2)
可以排序后,用一个指针记录第二次攻击进行到哪了(根据第一个式子,单调性)
((f1-d1)+(f2-d2)>=C-n)
记录(f2-d2)的最大值即可
注:
搜索时判重,若同一层出现了一样的值则无效
按理说讽刺值一样是应是保留天数少的,但(L)不一定一样,我们必须让它搜下去,若直接搜要爆掉
这样判可以保证数的构造唯一,(L)唯一,不会漏,也不多
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
#define ll long long
unordered_map<ll,bool>mp;
pair<int,int>dam[1111111];
#define fi(i) dam[i].first
#define se(i) dam[i].second
struct node{int i,f,l;};
const int N=304;
int n,m,day,tot,mx,mc;
int a[N],w[N],c[N],g[N][N];
void bfs(){
queue<node>q;
q.push((node){1,1,0});
while(!q.empty()){
node u=q.front();q.pop();
if(u.i==day)continue;
q.push((node){u.i+1,u.f,u.l+1});
if(u.l>1&&(ll)u.f*u.l<=mx&&!mp[(ll)u.f*u.l*100+u.i+1]){
q.push((node){u.i+1,u.f*u.l,u.l});
dam[++tot]=make_pair(u.f*u.l,u.i+1);
mp[(ll)u.f*u.l*100+u.i+1]=1;
}
}
}
int main(){
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();
for(int i=1;i<=m;i++)mx=max(mx,c[i]=read());
for(int i=1;i<=n;i++)
for(int j=a[i];j<=mc;j++){
g[i][j-a[i]]=max(g[i][j-a[i]],g[i-1][j]+1);
g[i][min(mc,j-a[i]+w[i])]=max(g[i][min(mc,j-a[i]+w[i])],g[i-1][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=mc;j++)day=max(day,g[i][j]);
bfs();
sort(dam+1,dam+tot+1);
for(int i=1,fl,mn;i<=m;i++){
if(c[i]<=day){puts("1");continue;}
fl=0;mn=1e9;
for(int j=tot,k=1;j;j--){
while(k<=tot&&fi(j)+fi(k)<=c[i]){
mn=min(mn,se(k)-fi(k));
++k;
}
if(mn+c[i]-fi(j)<=day-se(j)){fl=1;break;}
if(fi(j)<=c[i]&&c[i]-fi(j)<=day-se(j)){fl=1;break;}
}
if(fl==1)puts("1");
else puts("0");
}
return (0-0);
}