題面
BZOJ
洛谷
LOJ
人們總是難免會碰到大佬。他們趾高氣昂地談論凡人不能了解的算法和資料結構,走到任何一個地方,大佬的氣場
就能讓周圍的人吓得瑟瑟發抖,不敢言語。你作為一個OIER,面對這樣的事情非常不開心,于是發表了對大佬不敬
的言論。大佬便對你開始了報複,你也不示弱,揚言要打倒大佬。現在給你講解一下什麼是大佬,大佬除了是神犇
以外,還有着強大的自信心,自信程度可以被量化為一個正整數 C(1<=C<=10^8),想要打倒一個大佬的唯一方法
是摧毀 Ta的自信心,也就是讓大佬的自信值等于 0(恰好等于 0,不能小于 0 )。由于你被大佬盯上了,是以你
需要準備好 n(1<=n<=100)天來和大佬較量,因為這 n天大佬隻會嘲諷你動搖你的自信,到了第n+1天,如果大佬發
現你還不服,就會直接虐到你服,這樣你就喪失鬥争的能力了。你的自信程度同樣也可以被量化,我們用 mc (1 <
= mc <= 100)來表示你的自信值上限。在第i天(i>=1),大佬會對你發動一次嘲諷,使你的自信值減小a[i],如
果這個時刻你的自信值小于0了,那麼你就喪失鬥争能力,也就失敗了(特别注意你的自信值為0的時候還可以繼續
和大佬鬥争)。在這一天,大佬對你發動嘲諷之後,如果你的自信值仍大于等于0,你能且僅能選擇如下的行為之
一:
1.還一句嘴,大佬會有點驚訝,導緻大佬的自信值C減小1。
2.做一天的水題,使得自己的目前自信值增加 w[i],并将新自信值和自信值上限 mc比
較,若新自信值大于mc,則新自信值更新為mc。例如,mc=50,目前自信值為40,若
w[i]=5,則新自信值為45,若w[i]=11,則新自信值為50。
3.讓自己的等級值L加1。
4.讓自己的諷刺能力F乘以自己目前等級L,使諷刺能力F更新為F*L。
5.怼大佬,讓大佬的自信值C減小F。并在怼完大佬之後,你自己的等級L自動降為0,諷刺能力F降為1。
由于怼大佬比較掉人品,是以這個操作隻能做不超過2次。特别注意的是,在任何時候,你不能讓大佬的自信值為
負,因為自信值為負,對大佬來說意味着屈辱,而大佬但凡遇到屈辱就會進化為更厲害的大佬直接虐飛你。在第1
天,在你被攻擊之前,你的自信是滿的(初始自信值等于自信值上限mc),你的諷刺能力F是1,等級是0。現在由
于你得罪了大佬,你需要準備和大佬正面杠,你知道世界上一共有m(1<=m<=20)個大佬,他們的嘲諷時間都是 n
天,而且第 i天的嘲諷值都是 a[i]。不管和哪個大佬較量,你在第i天做水題的自信回漲都是w[i]。這m個大佬中
隻會有一個來和你較量(n天裡都是這個大佬和你較量),但是作為你,你需要知道對于任意一個大佬,你是否能
摧毀他的自信,也就是讓他的自信值恰好等于0。和某一個大佬較量時,其他大佬不會插手。
Input
第一行三個正整數n,m,mc。分别表示有n天和m個大佬,你的自信上限為mc。
接下來一行是用空格隔開的n個數,其中第i(1<=i<=n)個表示a[i]。
接下來一行是用空格隔開的n個數,其中第i(1<=i<=n)個表示w[i]。
接下來m行,每行一個正整數,其中第k(1<=k<=m)行的正整數C[k]表示第k個大佬的初
始自信值。
1 ≤n,mc ≤100; 1≤m≤20; 1≤a[i],w[i]≤mc; 1≤C[i] ≤10
Output
共m行,如果能戰勝第k個大佬(讓他的自信值恰好等于0),那麼第k行輸出1,否則輸出0。
Sample Input
10 20 100
22 18 15 16 20 19 33 15 38 49
92 14 94 92 66 94 1 16 90 51
4
5
9
338
5222
549
7491
9
12
3288
3
1
2191
833
3
6991
2754
3231
360
6
Sample Output
1
1
1
1
1
1
1
1
1
題解
這題好神啊。
首先仔細觀察幾種操作,發現和自己的自信值有關的隻有一個
是以,自己死不死與怼大佬無關。
是以,相當于拆成兩個部分,一個是怼大佬,另外一個是讓自己的自信值大于 0 0
是以,我們先做一次dpdp,求出最多可以空出多少天來怼大佬,也就是刷水題的最少次數。
這樣,恢複自信與怼大佬兩個分開,互相不影響。
現在的問題就變成了給你 N N 天,能否怼死大佬
我們怼大佬隻與兩個因素有關:天數和嘲諷值。
是以,求出所有的可行的天數和嘲諷值的集合,按照嘲諷值從大到小排序。
不怼或者怼一次解決大佬的情況很容易判斷(如果你隻判斷這個就可以拿到4040分了。。)
現在要解決的問題是怼兩次大佬。
不妨設兩次怼大佬花費的天數分别是 d1,d2 d 1 , d 2 ,總共可以怼 D D 天
嘲諷值分别是f1,f2f1,f2
我們可以列出不等式:
f1+f2<=C,f1+f2+(D−d1−d2)>=C f 1 + f 2 <= C , f 1 + f 2 + ( D − d 1 − d 2 ) >= C
考慮按照 f f 為第一關鍵字,dd為第二關鍵字排序,
現在維護兩個指針,分别從大往小和從小往大枚舉,每次保證 fi+fj<=C f i + f j <= C
因為我們固定了一個方向,不妨固定了 fi f i
是以,此時的定值是 fi,di,D,C f i , d i , D , C
那麼,這個時候要求的就是 f2−d2 f 2 − d 2 的最大值
在從小到大掃的過程中,顯然是單調的,是以不需要再從頭開始掃,直接繼承上一次的指針位置繼續向後即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111
#define ft(i) (zt[i].first)
#define sd(i) (zt[i].second)
inline int read()
{
RG int x=,t=;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-,ch=getchar();
while(ch<='9'&&ch>='0')x=x*+ch-,ch=getchar();
return x*t;
}
int f[MAX][MAX];
int n,m,MC,Day,a[MAX],w[MAX],C[MAX];
struct Node{int i,F,L;};
pair<int,int> zt[];
int tot,mx;
int MOD=;
struct Hash
{
struct Line{int x,y,next;}e[];
int h[+],cnt;
void Add(int x,int y)
{
int pos=(l*x*+y)%MOD;
e[++cnt]=(Line){x,y,h[pos]};h[pos]=cnt;
}
bool Query(int x,int y)
{
int pos=(l*x*+y)%MOD;
for(int i=h[pos];i;i=e[i].next)
if(e[i].x==x&&e[i].y==y)return true;
return false;
}
}Map;
void BFS()
{
queue<Node> Q;Q.push((Node){,,});
while(!Q.empty())
{
Node u=Q.front();Q.pop();
if(u.i==Day)continue;
Q.push((Node){u.i+,u.F,u.L+});
if(u.L>&&l*u.F*u.L<=l*mx&&!Map.Query(u.F*u.L,u.i+))
{
Q.push((Node){u.i+,u.F*u.L,u.L});
zt[++tot]=make_pair(u.F*u.L,u.i+);
Map.Add(u.F*u.L,u.i+);
}
}
}
int main()
{
n=read();m=read();MC=read();
for(int i=;i<=n;++i)a[i]=read();
for(int i=;i<=n;++i)w[i]=read();
for(int i=;i<=m;++i)mx=max(mx,C[i]=read());
for(int i=;i<=n;++i)
for(int j=a[i];j<=MC;++j)
{
f[i][j-a[i]]=max(f[i-][j]+,f[i][j-a[i]]);
f[i][min(j-a[i]+w[i],MC)]=max(f[i-][j],f[i][min(j-a[i]+w[i],MC)]);
}
for(int i=;i<=n;++i)
for(int j=;j<=MC;++j)Day=max(Day,f[i][j]);
BFS();sort(&zt[],&zt[tot+]);
for(int i=;i<=m;++i)
{
if(C[i]<=Day){puts("1");continue;}
bool fl=false;int mm=;
for(int j=tot,k=;j;--j)
{
while(k<tot&&ft(k)+ft(j)<=C[i])
mm=min(mm,sd(k)-ft(k)),++k;
if(mm+C[i]-ft(j)<=Day-sd(j)){fl=true;break;}
if(ft(j)<=C[i]&&C[i]-ft(j)<=Day-sd(j)){fl=true;break;}
}
fl?puts("1"):puts("0");
}
return ;
}