• 18.9.20 考试总结


    这道题是一道$dp$啊.. 思路都对了 但是我没有考虑到所有的转移情况都可以变成两堆进行处理

    所以我的想法是$dp[i][j]$表示$i$个盘子在$j$个柱子里转移 

    然后我每次是枚举分成的堆数 然后取$min$ 如果只考虑变成两堆转移就会简单很多

    然后要知道$n$个盘子在三个柱子里转移的步数是$2^{n} - 1$

    方程 

              $dp[i][j] = min(2 * dp[k][j] + dp[i - k][j - 1])$

    相当于先把上面一坨挪到一个柱子上 再把另外的用剩下的柱子转移 最后再把原先那一坨挪回去

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 200;
    int n,m;
    ll p[N],dp[N][N];
    
    void Init( ) {
        
        scanf("%d%d",& n,& m);
        p[0] = 1;
        for(int i = 1;i <= 63;i ++) p[i] = p[i - 1] * 2;
    }
    
    void Solve( ) {
        
        memset(dp,0x3f,sizeof(dp));
        for(int i = 1;i <= n;i ++) dp[i][3] = p[i] - 1;
        for(int i = 1;i <= m;i ++) dp[0][i] = 0,dp[1][i] = 1,dp[2][i] = 3;
        for(int i = 1;i <= n;i ++) {
            for(int j = 4;j <= m;j ++) {
                for(int k = 1;k <= i;k ++) {
                    dp[i][j] = min(dp[i][j], 2 * dp[k][j] + dp[i - k][j - 1]);
                }  
            }
        }
        printf("%lld
    ",dp[n][m]);
    }
    
    int main( ) {
        
        freopen("hanoi.in","r",stdin);
        freopen("hanoi.out","w",stdout);
        Init( );
        Solve( );
    }

    这道题我考试的时候竟然$A$了 qwqwqwqwqwq

    当时考的时候乱搞搞出来的规律... 证明一下发现对了...

    我们按照排名从前往后处理每个位置的值 然后因为是从前往后搞的 所以现在填的位置肯定比前一个要排名靠后

    所以我们比较排名上一个的后面的位置排名$pre$和现在这个位置$now$的排名 如果$rank pre < rank now$ 

    那么就说明我现在这个位置可以和上个位置填的字母一样 因为我后面的字母会帮助我把排名提起来

    反之则必须自己帮自己 因为我后面的字符串没有前面的厉害 必须自己把排名搞上去

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2 * 1e5 + 5;
    int n,a[N],s[N],pos[N];
    
    void Init( ) {
        
        scanf("%d",& n);
        for(int i = 1;i <= n;i ++) {
            scanf("%d",& a[i]);
            pos[a[i]] = i;
        }
        a[n + 1] = -1;
    }
    
    void Solve( ) {
        
        int ma = 0,now = 0;
        for(int i = 1;i <= n;i ++) {
            int p = pos[i];
            if(i == 1) {
                s[p] = now; ma = max(ma,a[p + 1]);
            }
            else {
                if(a[p + 1] > ma) {
                    s[p] = now; ma = max(a[p + 1],ma);
                }
                else {
                    s[p] = ++ now; ma = a[p + 1];
                }
            }
        }
        if(now > 25) {
            printf("-1"); return ;
        }
        for(int i = 1;i <= n;i ++) printf("%c",s[i] + 'a');
    }
    
    int main( ) {
        
        freopen("rank.in","r",stdin);
        freopen("rank.out","w",stdout);
        Init( );
        Solve( );
    }

    这道题是以前讲过的原题啊.. 而且还讲过两次

    然后我每次都听懂了.. 遇到题仍然还是写不来... 题解写得蛮好的 我复制一波

    化简一波发现

            $f[u] = du + sum f[v]$          $v$是$u$的所有孩子,$du$是那个点的度数

            $g[u] = du + g[fa] + sum f[v]$             $v$是$fa$不包括$u$的所有孩子

    然后维护每条到根节点链的$f,g$之和 然后用$lca$作作差即可

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int P = 20;
    const int N = 1e5 + 5;
    const int MOD = 1e9 + 7;
    int n,m,head[N],nex[2 * N],tov[2 * N],d[N];
    int tot,anc[N][P + 1],fa[N],dep[N];
    int disf[N],disg[N];
    ll f[N],g[N];
    
    void moc(ll & a,ll b) {
        
        a = (a + b) % MOD;
    }
    
    void add(int u,int v) {
        
        tot ++;
        nex[tot] = head[u];
        tov[tot] = v;
        head[u] = tot;
        d[v] ++; d[u] ++;
    }
    
    void Dfs_f(int u, int fat) {
        
        anc[u][0] = fat;
        for(int i = 1;i <= P;i ++) anc[u][i] = anc[anc[u][i - 1]][i - 1];
        fa[u] = fat;
        bool tag = false; 
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(v == fat) continue;
            dep[v] = dep[u] + 1;
            Dfs_f(v, u);
            moc(f[u], f[v] + 1);
        }
        moc(f[u], 1);
    }
    
    void Dfs_g(int u, int fat) {
        
        ll s = 0;
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(v == fat) moc(s,g[u] + 1);
            else moc(s,f[v] + 1);
        }
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(v == fat) continue;
            g[v] = s - f[v];
            Dfs_g(v, u);
        }
    }
    
    int find_lca(int u,int v) {
        
        if(dep[u] < dep[v]) swap(u, v);
        int del = dep[u] - dep[v];
        for(int i = P;i >= 0;i --) if(del & (1 << i)) u = anc[u][i];
        if(u == v) return u;
        for(int i = P;i >= 0;i --)
            if(anc[u][i] != anc[v][i])
                v = anc[v][i], u = anc[u][i];
        return fa[u];
    }
    
    void Get(int u) {
        
        disf[u] = (disf[fa[u]] + f[u]) % MOD;
        disg[u] = (disg[fa[u]] + g[u]) % MOD;
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(v == fa[u]) continue;
            Get(v);
        }
    }
    
    void Init( ) {
        
        scanf("%d%d",& n,& m);
        for(int i = 1;i < n;i ++) {
            int u,v;
            scanf("%d%d",& u,& v);
            add(u, v); add(v, u);
        }
        Dfs_f(1, 0); Dfs_g(1, 0);
        f[1] = 0;
        Get(1);
    }
    
    void Solve( ) {
        
        while(m --) {
            int u,v;
            scanf("%d%d",& u,& v);
            int lca = find_lca(u, v);
            ll ans = ((disf[u] - disf[lca] + disg[v] - disg[lca]) % MOD + MOD) % MOD;
            printf("%lld
    ",ans);
        }
    }
    
    int main( ) {
        
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        Init( );
        Solve( );
    }
  • 相关阅读:
    java内部类
    接口与继承
    数据结构
    数据I/O流
    课程总结
    第六次实训作业异常处理
    常用类的课后作业
    窗口实训1
    实训作业4
    实训作业3
  • 原文地址:https://www.cnblogs.com/Rubenisveryhandsome/p/9682065.html
Copyright © 2020-2023  润新知