树形dp,拆位思想学习

过年了,最近甚为咸鱼,赶紧来练练代码,顺便练练用Java写算法(写的好慢。。)

  1. https://ac.nowcoder.com/acm/contest/370/C
    签到题,只需要记录每行,每列最新的记录,然后对于一个点(x,y)求x行和y列刷新的最大值即可,复杂度O(mn)
import java.util.Scanner;

public class Main{

    static private long mod = 1000000007;

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt(), m = cin.nextInt(),  T = cin.nextInt();
        int [][] arr = new int[3][Math.max(n, m)+5];
        for(int i=1; i<=T; i++){
            arr[cin.nextInt()][cin.nextInt()] = i;
        }

        for(int i=1; i<=n; i++){
            for(int j=1; j<=m; j++){
                System.out.print(Math.max(arr[1][i], arr[2][j]) + " ");
            }
            System.out.println();
        }
    }
}

  1. https://ac.nowcoder.com/acm/contest/370/J
    最简化根式,暴力抽出所有平方因子就可以,复杂度O(T√n)
import java.util.Scanner;

public class Main{

    static private long mod = 1000000007;
    static private int [] arr = new int[1000];

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int T = cin.nextInt();
        for(int i=1; i<=T; i++){
            int a = cin.nextInt();
            if(a < 0){
                System.out.println(-1);
            }else {
                int sqr = ((int) Math.sqrt(a)), ans = 1;
                for(int j = sqr; j>0; j--){
                    if(a % (j*j) == 0){
                        ans *= j;
                        a /= (j*j);
                    }
                }
                System.out.println(ans + " " + a);
            }
        }

    }
}

  1. https://ac.nowcoder.com/acm/contest/370/F
    树形dp,M = N-1,所以是树。假设v是u的其中一个孩子,w为权重,递推式:dp[u] += min(dp[u], w)。注意dfs的时候,要把父亲删掉,
import java.util.*;

public class Main{

    static private final int mod = 1000000007, max = 100005;
    static private long [] dp = new long[max];
    private static Map<Integer, List<Edge>> g = new HashMap<>();

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt(), m = cin.nextInt(), s = cin.nextInt();


        //邻接矩阵存不下,采用邻接表
        for(int i=0; i<m; i++){
            int from = cin.nextInt(), to = cin.nextInt(), w = cin.nextInt();
            add(from, to, w);
            add(to, from, w);
        }

        //树形dp
        dfs(s, 0);
        System.out.println(dp[s]);
    }

    private static class Edge{

        int from, to, w;

        public Edge(int from, int to, int w) {
            this.from = from;
            this.to = to;
            this.w = w;
        }
    }

    private static void add(int from, int to, int w){
        if(g.containsKey(from)){
            g.get(from).add(new Edge(from, to, w));
        }else {
            List<Edge> list = new ArrayList<>();
            list.add(new Edge(from, to, w));
            g.put(from, list);
        }
    }

    private static void dfs(int root, int f){
        for(Edge e : g.get(root)){
            if(e.to == f){//碰到的是父亲
                continue;
            }
            dfs(e.to, root);
            dp[root] += Math.min(dp[e.to], e.w);
        }
        if(dp[root] == 0){
            dp[root] = Long.MAX_VALUE;
        }
    }
}

  1. https://ac.nowcoder.com/acm/contest/370/I
    首先要对递推式进行合并,可以得到在这里插入图片描述
    然后根据异或运算的特性,1只对0有贡献,0只对1有贡献。拆位,一位一位来看,从二进制的角度进行运算,设从A0 - Ai的第j位共有wA[j][0]个0,wA[j][1]个1,wB同理。可得C的第j位是wA[j][0]*wB[j][1] + wA[j][1]*wB[j][0],然后转为十进制即可。注意数据溢出。
import java.util.Scanner;

public class Main{

    static private final int mod = 1000000007, max = 100005;
    static private long [][] wA = new long[40][2], wB = new long[40][2];
    static private int [] A = new int[max], B = new int[max];

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        for(int i=1; i<=n; i++){
            A[i] = cin.nextInt();
        }
        for(int i=1; i<=n; i++){
            B[i] = cin.nextInt();
        }
        for(int i=1; i<=n; i++){
            long c = 0;
            for(int j=0; j<=30; j++){
                //统计第ai对于第j位的贡献
                wA[j][(A[i]>>j)&1]++;
                wB[j][(B[i]>>j)&1]++;
                c = (c + (1<<j) * (wA[j][0]*wB[j][1] + wA[j][1]*wB[j][0]))%mod;
            }
            System.out.print(c + " ");
        }
        System.out.println();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值