ABC 319F - Fighter Takahashi

文章讨论了一种涉及药水获取的决策问题,通过贪心策略和优先级队列分析,如何在有限药水和树形结构的敌人战斗中找到最优的药水使用顺序,以最大化提升力量并击败所有敌人。
摘要由CSDN通过智能技术生成

Here 

解题思路

  • 首先存在一种贪心策略,一定由弱到强选择击败的敌人
  • 保证自己面对一个敌人时,是可能的最大力量
  • 考虑没有药水
  • 则用bfs将能到的敌人由弱到强依次挑战,并不断增加力量,直到没法继续扩展
  • 若当前力量大于最强的敌人,则可以击败所有人,输出Yes
  • 现在有了药水,由于药水在节点上,且为树形结构
  • 要拿到某一个药水可能要遇上很强的敌人,导致无法取到该药水提升实力
  • 但若先去其他药水,然后再打败一些敌人提升实力,就可能打败那个Boss
  • 所以药水的取用顺序会存在一个最优方案
  • 考虑到药水最多只有10
  • 所以不用管药水的最优是如何取用的,直接状压出所有顺序
  • 先处理出不考虑药水的答案,则将其bfs中能直接取到的药水,放入状态
  • s=111_2,t=101_2,011_2,110_2,t<s
  • 对于当前状态s,则可以到达它的状态都被处理了,所以f[s]决策完毕
  • 每次从一个已经决策完的状态,bfs下一个可能的状态,每次多取一个能直接取到的药水  (更多的到后面更新)
  • 对于不可能存在的状态,f[s]=0,不会被更新,直接Pass
  • 再过程中,若当前力量大于最强的敌人,则可以击败所有人,,输出Yes
  • 若所有可以的顺序决策完(一定包含最优顺序)都不大于最强的敌人,则寄

import java.io.*;
import java.math.BigInteger;
import java.util.*;


//implements Runnable
public class Main {
    static long md=(long)998244353;
    static long Linf=Long.MAX_VALUE/2;
    static int inf=Integer.MAX_VALUE/2;
    static int N=1000010;
    static int n=0;
    static int m=0;

    static
    class Node{
        long x;
        long y;
        public Node() {

        }
        public Node(long u,long v) {
            x=u;
            y=v;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node now = (Node) o;
            return x==now.x&&y==now.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }
    static int qm2(int a,int b) {
        int res=1;

        while(b>0) {
            if((b&1)==1)res=res*a;
            a=a*a;
            b>>=1;
        }
        return res;
    }


    static
    class Edge{
        int fr,to,nxt;
        public Edge(int u,int v){
            fr=u;
            to=v;
        }
    }
    static  Edge[] e;
    static  int[] head;
    static  int cnt=0;
    static void addEdge(int fr,int to){
        cnt++;
        e[cnt]=new Edge(fr,to);
        e[cnt].nxt=head[fr];
        head[fr]=cnt;
    }
    static long[] p;
    static long[] t;
    static long[] s;
    static long[] g;
    static int[] med;
    static long[] f;
    static long mx;

    static boolean get_fu_nxt(int u){//u已经处理完了,看能往后扩展多取一个药水的情况
        boolean[] vis=new boolean[n+1];
        PriorityQueue<Node> q=new PriorityQueue<>((o1,o2)->{
            if(o1.y-o2.y>0)return 1;
            else if(o1.y-o2.y<0)return -1;
            else return 0;
        });
        q.add(new Node(1,0));//id,s
        while(!q.isEmpty()){//f[u]为药水选取状态为u的最大power,看在其能到的点中有没有药水
            Node now=q.peek();q.poll();
            long ns=now.y;
            int x=(int)now.x;
            if(ns>f[u])break;
            vis[x]=true;
            for(int i=head[x];i>0;i=e[i].nxt){
                int v=e[i].to;
                if(t[v]==1||((u>>med[v])&1)==1)q.add(new Node(v,s[v]));
                else vis[v]=true;//可以取到的药水
            }
        }
        for(int j=1;j<=n;++j){
            if(med[j]!=-1&&vis[j]&&((u>>med[j])&1)==0){//拿一个药水,更新状态
                long sum=f[u]*g[j];
                int nu=u|(1<<med[j]);
                while(!q.isEmpty())q.poll();
                q.add(new Node(1,0));
                while(!q.isEmpty()){
                    Node now=q.peek();q.poll();
                    long ns=now.y;
                    int x=(int)now.x;
                    if(ns>sum)break;
                    if(ns!=0)sum=Math.min(inf,sum+g[x]);
                    if(sum>=mx)return true;
                    for(int i=head[x];i>0;i=e[i].nxt){
                        int v=e[i].to;
                        if(!vis[v])q.add(new Node(v,s[v]));//新扩展的点用以更新状态
                        else{
                            if(t[v]==2&&((nu>>med[v])&1)==0)continue;
                            q.add(new Node(v,0));//在u到过的点,不更新只用于扩展找新点
                        }
                    }
                }
                f[nu]=Math.max(f[nu],sum);//更新状态
            }
        }
        return false;
    }
    static boolean get_f0(){
        PriorityQueue<Node> q=new PriorityQueue<>((o1,o2)->{//贪心策略,先拿小的
            if(o1.y-o2.y>0)return 1;
            else if(o1.y-o2.y<0)return -1;
            else return 0;
        });
        q.add(new Node(1,0));//id,s
        while(!q.isEmpty()){
            Node now=q.peek();q.poll();
            long ns=now.y;
            int x=(int)now.x;
            if(ns>f[0])break;
            f[0]=Math.min(inf,f[0]+g[x]);
            if(f[0]>=mx)return true;
            for(int i=head[x];i>0;i=e[i].nxt){
                int v=e[i].to;
                if(t[v]==1)q.add(new Node(v,s[v]));
                //状态为0,不拿药水
            }
        }
        return false;
    }
    static void solve() throws Exception{
        AReader input=new AReader();
//		Scanner input=new Scanner(System.in);
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        String al="abcdefghijklmnopqrstuvwxyz";
        char[] ac=al.toCharArray();

//		int T=input.nextInt();
//		while(T>0) {
//			T--;
//  		}
        m=-1;mx=0;
        n=input.nextInt();
        p=new long[n+1];
        t=new long[n+1];
        s=new long[n+1];
        g=new long[n+1];
        med=new int[n+1];

        e=new Edge[n+1];
        head=new int[n+1];
        cnt=0;

        for(int i=2;i<=n;++i){
            p[i]=input.nextLong();
            t[i]=input.nextLong();
            s[i]=input.nextLong();
            g[i]=input.nextLong();
            addEdge((int)p[i],i);
            mx=Math.max(mx,s[i]);
        }
        for(int i=2;i<=n;++i){
            if(t[i]==2){
                m++;
               med[i]=m;
            }else med[i]=-1;
        }
        int st=qm2(2,m+1);
        f=new long[st+1];
        f[0]=1;
        if(get_f0())out.println("Yes");
        else{
            boolean ok=false;
            for(int i=0;i<st;++i){
                if(f[i]==0)continue;//该状态不存在
                if(get_fu_nxt(i)){
                    ok=true;
                    break;
                }
            }
            if(ok)out.println("Yes");
            else out.println("No");
        }
        out.flush();
        out.close();
    }
    public static void main(String[] args) throws Exception{
        solve();
    }
    //	public static final void main(String[] args) throws Exception {
//		  new Thread(null, new Tx2(), "线程名字", 1 << 27).start();
//	}
//		@Override
//		public void run() {
//			try {
//				//原本main函数的内容
//				solve();
//
//			} catch (Exception e) {
//			}
//		}
    static
    class AReader{
        BufferedReader bf;
        StringTokenizer st;
        BufferedWriter bw;

        public AReader(){
            bf=new BufferedReader(new InputStreamReader(System.in));
            st=new StringTokenizer("");
            bw=new BufferedWriter(new OutputStreamWriter(System.out));
        }
        public String nextLine() throws IOException{
            return bf.readLine();
        }
        public String next() throws IOException{
            while(!st.hasMoreTokens()){
                st=new StringTokenizer(bf.readLine());
            }
            return st.nextToken();
        }
        public char nextChar() throws IOException{
            //确定下一个token只有一个字符的时候再用
            return next().charAt(0);
        }
        public int nextInt() throws IOException{
            return Integer.parseInt(next());
        }
        public long nextLong() throws IOException{
            return Long.parseLong(next());
        }
        public double nextDouble() throws IOException{
            return Double.parseDouble(next());
        }
        public float nextFloat() throws IOException{
            return Float.parseFloat(next());
        }
        public byte nextByte() throws IOException{
            return Byte.parseByte(next());
        }
        public short nextShort() throws IOException{
            return Short.parseShort(next());
        }
        public BigInteger nextBigInteger() throws IOException{
            return new BigInteger(next());
        }
        public void println() throws IOException {
            bw.newLine();
        }
        public void println(int[] arr) throws IOException{
            for (int value : arr) {
                bw.write(value + " ");
            }
            println();
        }
        public void println(int l, int r, int[] arr) throws IOException{
            for (int i = l; i <= r; i ++) {
                bw.write(arr[i] + " ");
            }
            println();
        }
        public void println(int a) throws IOException{
            bw.write(String.valueOf(a));
            bw.newLine();
        }
        public void print(int a) throws IOException{
            bw.write(String.valueOf(a));
        }
        public void println(String a) throws IOException{
            bw.write(a);
            bw.newLine();
        }
        public void print(String a) throws IOException{
            bw.write(a);
        }
        public void println(long a) throws IOException{
            bw.write(String.valueOf(a));
            bw.newLine();
        }
        public void print(long a) throws IOException{
            bw.write(String.valueOf(a));
        }
        public void println(double a) throws IOException{
            bw.write(String.valueOf(a));
            bw.newLine();
        }
        public void print(double a) throws IOException{
            bw.write(String.valueOf(a));
        }
        public void print(char a) throws IOException{
            bw.write(String.valueOf(a));
        }
        public void println(char a) throws IOException{
            bw.write(String.valueOf(a));
            bw.newLine();
        }
    }
}



 

  • 21
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值