BZOJ 4828: [AH2017/HNOI2017]大佬 Dp

title

BZOJ 4828

LUOGU 3724

题面巨长,再次不想贴了

analysis

细读题面,可以发现和自己自信值有关的就一项,所以题目再三强调的你不能死,其实是句废话。

但是最终答案是问是否能怼死大佬,而跟着有关的就天数和嘲讽值这两个因素,所以,好像清晰了点儿(但是好像还是改变不了这是个神仙题的事实)。

下面就把可行的天数,嘲讽值都求出来,然后再把嘲讽值从小到大排个序(当然,这两个用个 \(pair\) 连起来,不是让分开搞的)。

不怼,或者怼一次就把大佬怼死了(这还是大佬吗)的情况比较容易判断,所以...

那么问题就是怼两次怼死他的情况:

然后,我就...不会了...

下面就是看过 yyb \(blog\) 后才会的。

不妨设两次怼大佬花费的天数分别是 \(d_1,d_2\) ,总共可以怼 \(D\) 天,嘲讽值分别是 \(f_1,f_2\)

我们可以列出不等式:
\[ f_1+f_2<=C,f_1+f_2+(D−d_1−d_2)>=C \]

考虑按照 \(f\) 为第一关键字, \(d\) 为第二关键字排序,

现在维护两个指针,分别从大往小和从小往大枚举,每次保证 \(f_i+f_j<=C\)

因为我们固定了一个方向,不妨固定了 \(f_i\) 所以,此时的定值是 \(f_i,d_i,D,C\)

那么,这个时候要求的就是 \(f_2−d_2\) 的最大值

在从小到大扫的过程中,显然是单调的,因此不需要再从头开始扫,直接继承上一次的指针位置继续向后即可。

code

#include<bits/stdc++.h>

#define mp std::make_pair
typedef std::pair<int,int> pii;
const int maxn=111,mod=1000007;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }

struct Hash_Table
{
    int spot[mod+3],ver[mod+3],Next[mod+3],head[mod+1],len;
    inline void add(int x,int y)
    {
        int pos=(1ll*x*101+y)%mod;
        spot[++len]=x,ver[len]=y,Next[len]=head[pos],head[pos]=len;
    }

    inline bool query(int x,int y)
    {
        int pos=(1ll*x*101+y)%mod;
        for (int i=head[pos]; i; i=Next[i])
            if (spot[i]==x && ver[i]==y) return true;
        return false;
    }
} M;

pii o[mod+3];
struct Orz{int i,F,L;};
int tot,mx,Day;
inline void bfs()
{
    std::queue<Orz>q;
    q.push((Orz){1,1,0});
    while (!q.empty())
    {
        Orz x=q.front();
        q.pop();
        if (x.i==Day) continue;
        q.push((Orz){x.i+1,x.F,x.L+1});
        if (x.L>1 && 1ll*x.L*x.F<=1ll*mx && !M.query(x.F*x.L,x.i+1))
        {
            q.push((Orz){x.i+1,x.F*x.L,x.L});
            o[++tot]=mp(x.F*x.L,x.i+1);
            M.add(x.F*x.L,x.i+1);
        }
    }
}

int a[maxn],w[maxn],c[maxn],f[maxn][maxn];
int main()
{
    int n,m,mc;
    read(n);read(m);read(mc);
    for (int i=1; i<=n; ++i) read(a[i]);
    for (int i=1; i<=n; ++i) read(w[i]);
    for (int i=1; i<=m; ++i) read(c[i]),chkMax(mx,c[i]);
    for (int i=1; i<=n; ++i)
        for (int j=a[i]; j<=mc; ++j)
        {
            chkMax(f[i][j-a[i]],f[i-1][j]+1);
            chkMax(f[i][min(j-a[i]+w[i],mc)],f[i-1][j]);
        }
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=mc; ++j) chkMax(Day,f[i][j]);
    bfs();
    std::sort(o+1,o+tot+1);
    for (int i=1; i<=m; ++i)
    {
        if (c[i]<=Day) { write(1,'\n'); continue; }
        int flag=0, mn=1e9;
        for (int j=tot, k=1; j; --j)
        {
            while (k<tot && o[k].first+o[j].first<=c[i]) chkMin(mn,o[k].second-o[k].first), ++k;
            if (mn+c[i]-o[j].first<=Day-o[j].second) { flag=1; break; }
            if (o[j].first<=c[i] && c[i]-o[j].first<=Day-o[j].second) { flag=1; break; }
        }
        write(flag,'\n');
    }
    IO::flush();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/G-hsm/p/11455917.html
今日推荐