[HNOI2017] 大佬 [DP/搜索]

Author Avatar
空気浮遊 2019年01月08日
  • 在其它设备中阅读本文章

是乱搞,,

Solution

首先可以发现你可以把空闲的最多操作数求出来

其次你可以发现一次怼人能得到的状态数有限

那么把所有状态爆搞出来

之后再强行枚举一发就能直接过掉这题了,,,

事实上算出来的最坏复杂度是 1.7e9,但是呢加了一些剪枝,所以大概也算能接受...?

Code

// Code by ajcxsu
// Problem: dalao

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define CLR(x, y) memset(x, y, sizeof(x))
using namespace std;
using namespace __gnu_pbds;

template<typename T> inline void gn(T &x) {
    char ch=getchar(); x=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0', ch=getchar();
}
template<typename T, typename ...Args> inline void gn(T &x, Args &...args) { gn(x), gn(args...); }

typedef long long ll;
gp_hash_table<ll, int> s[110];
int gat=0;
int rt=101;
void dfs(ll f, int l, int k) {
    if(f*l>100000000ll) return;
    if(k+1>gat) return;
    if(f*l<=100000000ll && (s[l].find(f*l)==s[l].end() || s[l][f*l]>k+1)) s[l][f*l]=k+1, dfs(f*l, l, k+1);
    dfs(f, l+1, k+1);
}

const int N=210, M=8.6e5;
int f[N][N], a[N], w[N], c[N];
struct Thing { int v, w; } t[M];
bool cmp(const Thing &a, const Thing &b) { return a.v<b.v; }
bool ans[N];

int main() {    
    int n, m, mc;
    gn(n, m, mc);
    for(int i=1;i<=n;i++) gn(a[i]);
    for(int i=1;i<=n;i++) gn(w[i]);
    for(int i=0;i<m;i++) gn(c[i]);
    CLR(f, 0x3f);
    f[0][mc]=0;
    for(int i=1;i<=n;i++) {
        for(int j=0;j<=2*mc;j++) {
            if(j+a[i]<=2*mc) f[i][j]=f[i-1][j+a[i]];
            if(j+a[i]-w[i]<=2*mc && j-w[i]>=0) f[i][j]=min(f[i][j], f[i-1][j+a[i]-w[i]]+1);
            gat=max(gat, i-f[i][j]);
            if(j>mc) f[i][mc]=min(f[i][j], f[i][mc]), f[i][j]=0x3f3f3f3f;
        }
    }
    dfs(1, 0, 0);
    int p=0;
    for(int i=0;i<=100;i++)
        for(auto it:s[i]) if(s[rt].find(it.first)==s[rt].end() || s[rt][it.first]>it.second) s[rt][it.first]=it.second;
    for(auto it:s[rt]) t[p++]={it.first, it.second};
    sort(t, t+p, cmp);
    for(int i=0;i<m;i++)
        for(int nc=0;nc<=gat;nc++) {
            if(c[i]-nc==0) ans[i]=1;
            if(s[rt].find(c[i]-nc)!=s[rt].end() && s[rt][c[i]-nc]+nc+1<=gat) ans[i]=1;
            for(int j=0;j<p && t[j].v<c[i]-nc && !ans[i];j++)
                if(s[rt].find(c[i]-nc-t[j].v)!=s[rt].end() && s[rt][c[i]-nc-t[j].v]+nc+t[j].w+2<=gat)
                    ans[i]=1;
        }
    for(int i=0;i<m;i++) printf("%d\n", ans[i]);
    return 0;
}