• bzoj4828 hnoi2017 大佬


    题目描述

    人们总是难免会碰到大佬。他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语。 你作为一个 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。和某一个大佬较量时,其他大佬不会插手。

    输入输出格式

    输入格式:

     

    第一行三个正整数 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 个大佬的初始自信值。

     

    输出格式:

     

    共 m 行,如果能战胜第 k 个大佬(让他的自信值恰好等于 0),那么第 k 行输出 1,否则输出 0。

    题意:

         一个大佬自信值为c,你的自信值为mc,大佬每天会减少你的自信值a[i],你可以选择刷水题让自己的自信值提高w[i],或者让c--,或者让自己等级L++,或者给使讽刺能力F*=L,或者怼大佬造成F的伤害(mc-=F),然后初始化L,F(L=0,F=1)。但是怼大佬只能小于等于两次,多个询问c,问能不能恰好归零c。

    题解:

    ①量太多,直接dp,掰了掰手指后发现:会大事不妙

    ②水题刷多了不好,预处理最大化不刷水题的天数,设计dpij表示第i天自信值为j时有多少天可以进行除刷水题以外的操作。dpij 有两种转移 不做刷和刷:即dpi-1,j+a[i] –> dpi,j  和  dpi-1,j+a[i] –> dpi,min(j+w[i],m);       (不要小看这个dp,大米兔认为写的话还是要理解得很清楚)

    ③现在我们可以在被大佬打压之余自由地安排剩下的人生:
    进行其余的操作,在经过一些神秘YY之后,如果利用哈希表判断一下F,L不重复,状态不多,可以暴力bfs出(d,f) 为用
    d天怼一次大佬可以造成恰好f的伤害,并且由于我们有水题神器,d天可以有f,d+1天就不需要f了,相当于您悠闲地再做一天水题就好了;

    ③下面我们对大佬打出精确的伤害:
    分类讨论,在剩下的D天里,可以做两件事:让c-1,让c-某个f;

    不做f   C[i] <= D;   

    一次f   C – (D-d) <= f <= C    d<=D;

    两次f   C – (D-d1-d2) <= f1 + f2 <= C    d1+d2<=D;

    (既不能把大佬XX成负数同时保证能XX完)

    零次和一次直接判断,两次的时候按f排序,f1变小,使f2变大并满足右边,维护左边的最大值,这样就保证扫一次就好了(另外不需要特判d1+d2<=D,因为反之式子一定不成立)!

    下面的代码记录了一个蒟蒻花了n天勇敢战胜m个大佬的故事:

     

     1 #include<cstdio>
     2 #include<istream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #define N 210
     7 #define M 2000100
     8 #define inf 0x3f3f3f3f
     9 #define ull unsigned long long
    10 using namespace std;
    11 typedef pair<int,int>pii;
    12 int n,m,mc,C[N],a[N],w[N],D,f[N][N],mxC;
    13 pii q[M];int top;
    14 struct node{int f,d,l;};
    15 queue<node> Q;
    16 const int sz = 2*1e7;
    17 struct Hash{
    18     struct Edge{int x,y,nt;ull w;}E[sz+1];int hd[sz+1],o;
    19     void ins(ull x,ull y){
    20         ull w = (x * 10101 + y * 101);
    21         E[++o] = (Edge){x,y,hd[w%sz],w};
    22         hd[w%sz] = o;
    23     }
    24     int query(ull x,ull y){
    25         ull w = (x * 10101 + y * 101);
    26         for(int i = hd[w%sz];i;i = E[i].nt)
    27             if(E[i].x==x&&E[i].y==y) return 1;
    28         return 0;
    29     }
    30 }H;
    31 char gc(){
    32     static char *p1,*p2,s[1000000];
    33     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
    34     return(p1==p2)?EOF:*p1++;
    35 }
    36 int rd(){
    37     int x = 0; char c = gc();
    38     while(c<'0'||c>'9') c = gc();
    39     while(c>='0'&&c<='9') x = x * 10 + c - '0',c = gc();
    40     return x;
    41 }
    42 void bfs(){
    43     Q.push((node){1,1,0}); 
    44     //q[++top] = make_pair(1,1);
    45     H.ins(1,0);
    46     while(!Q.empty()){
    47         node x = Q.front(); Q.pop();
    48         if(x.d>=D) continue;
    49         Q.push((node){x.f,x.d+1,x.l+1});
    50         if(x.l > 1 && x.f <= mxC/x.l && !H.query(x.l*x.f,x.l)){
    51             node tmp = (node){x.l*x.f,x.d+1,x.l}; 
    52             H.ins(tmp.f,tmp.l);
    53             q[++top] = make_pair(tmp.f,tmp.d);
    54             Q.push(tmp);
    55         }
    56     }
    57 }
    58 int main()
    59 {    //freopen("bzoj4828.in","r",stdin);
    60     //freopen("bzoj4828.out","w",stdout);
    61     n = rd(); m = rd(); mc = rd();
    62     for(int i = 1;i <= n;i++) a[i] = rd();
    63     for(int i = 1;i <= n;i++) w[i] = rd();
    64     for(int i = 1;i <= m;i++) mxC = max(mxC,C[i] = rd());
    65     memset(f,128,sizeof(f));f[0][mc] = 0;
    66     for(int i = 1;i <= n;i++){
    67         for(int j = 0;j <= mc - a[i];j++)
    68         f[i][j] = max(f[i][j],f[i - 1][j + a[i]] + 1),
    69         f[i][min(mc,j+w[i])] = max(f[i][min(mc,j+w[i])],f[i-1][j+a[i]]);
    70         for(int j = 0;j <= mc;j++) D =max(f[i][j],D);
    71     }
    72     bfs(); 
    73     sort(q+1,q+top+1);
    74     for(int i = 1;i <= m;i++){
    75         int mx = -inf,ans = 0;
    76         if(C[i]<=D) {puts("1"); continue;}
    77         for(int j = top,k = 0;j >= 1;j--){
    78             while(k<top && q[k+1].first + q[j].first <= C[i]) k++,mx = max(mx,q[k].first - q[k].second);
    79             if(q[j].first <= C[i] && q[j].first + D - q[j].second >= C[i]) {ans = 1; break;}
    80             if(q[j].first - q[j].second + mx + D >= C[i]) {ans = 1; break;}
    81         }
    82         printf("%d
    ",ans);
    83     }
    84     return 0;
    85 }//by tkys_Austin;

     

     

  • 相关阅读:
    程序员这生必须掌握的两种图形
    用一张组织架构图说清楚类和对象
    简单工厂、工厂方法、抽象工厂的比较与分析
    rabbitmq系列(一)初识rabbitmq
    【最新】经典面试100问,附答案
    使用wordPress搭建个人博客
    调试接口你还在用postman吗
    Token ,Cookie、Session傻傻分不清楚?
    你不可不知的自定义注解
    使用aop加解密http接口
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/8646040.html
Copyright © 2020-2023  润新知