• 暑假第十八测


    题解:

    第一题:nlogn LIS

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 100005;
    int a[M], f[M];
    int main(){
        freopen("lis.in","r",stdin);
        freopen("lis.out","w",stdout);
        int n, cnt = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
            if(a[i] > f[cnt])f[++cnt] = a[i];
            else {
                int pos = lower_bound(f+1, f+1+cnt, a[i]) - f;
                f[pos] = a[i];
            }
        }
        printf("%d
    ", cnt);
    }
    View Code

    第二题:树上背包,dp[u][i]表示以u为子树连续大小为i最少砍多少刀;答案就是max(dp[u][k] -1) 减去和父亲连的一条边

    dp[u][k] = min( dp[u][k],  dp[u][p] + dp[v][k - p] - 1) (我们一个一个子树考虑,多一棵树就可以少砍一条边)

    dp[u][1] = degree[u];

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    using namespace std;
    const int M = 155, inf = 1e8;
    int siz[M], n, k, h[M], dp[M][M], du[M], tot, zz = inf;
    struct edge{int v, nxt;}G[M << 1];
    void add(int u, int v){G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot;}
    
    void dfs(int u, int fa){
        //dp[u][0] = 0;
        if(u != 1)du[u]--;
        dp[u][1] = du[u];
        siz[u] = 1;
        int child = 0;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(v == fa)continue;
            dfs(v, u);
            child++;
            siz[u] += siz[v];
                
        }
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(v == fa)continue;
            int s1 = min(siz[u], k), s2;
                for(int p = s1; p > 1; p--){
                    s2 = min(p - 1, siz[v]);
                    for(int z = 1; z <= s2; z++){
                        if(dp[u][p - z] < inf)
                            dp[u][p] = min(dp[u][p], dp[u][p - z] + dp[v][z] - 1);
                    }
                }    
                
        }
        
        if(u != 1)zz = min(zz, dp[u][k] + 1);
        else zz = min(zz, dp[u][k]);
    }
    
    
    int main(){
        freopen("isolate.in","r",stdin);
        freopen("isolate.out","w",stdout);
        scanf("%d%d", &n, &k);
        int u, v;
        for(int i = 1; i < n; i++){
            scanf("%d%d", &u, &v);
            add(u, v); add(v, u);
            du[u]++; du[v]++;
        }
        //memset(mx, 127, sizeof(mx));
        memset(dp, 127, sizeof(dp));
        dfs(1, 0);
        /*for(int i = 1; i <= n; i++){
            
            for(int j = 1; j <= k; j++)printf("%d %d
    ", dp[i][j], dp[i][j]);
            printf("      %d
    ", i);
        }*/
            
        printf("%d
    ", zz);
    }
    View Code

    第三题:状压dp,原题

    #include<bits/stdc++.h>
    using namespace std;
    long long dp[12][1 << 11];
    int w[1 << 11][1 << 11], r, c;
    
    void dfs(int dep, int os, int ns){
        if(!dep) w[ns][++w[ns][0]] = os;
        else{
            if( ( (1<<(dep - 1)) & os ) == 0){
                dfs(dep - 1, os, ns + (1 << (dep - 1)));
            }
            else{
                dfs(dep - 1, os, ns);
                if(dep >= 2 && ( os & (1 << (dep - 2)) ) )
                    dfs(dep - 2, os, ns + (1 << (dep - 1)) + (1 << (dep - 2)));
            }
        }
    }
    
    void init(){
        
        for(int s1 = 0; s1 < (1 << r); s1++)
            dfs(r, s1, 0);
    }
    
    
    int main(){
        freopen("domino.in","r",stdin);
        freopen("domino.out","w",stdout);
        scanf("%d%d", &r, &c);
        if(r * c % 2){
            puts("0");return 0;
        }
        if(r > c)swap(r, c);
        init();
        dp[0][(1 << r) - 1] = 1;
        for(int i = 1; i <= c; i++){
            for(int s = 0; s < ( 1 << r ); s++){
                for(int k = 1; k <= w[s][0]; k++)
                    dp[i][s] += dp[i - 1][w[s][k]];
            }
        }
        printf("%I64d
    ",dp[c][(1 << r) - 1]);
    }
    View Code

    第四题:背包,dp[p][s]表示选择了总共p元,是否可以凑出s元;

    dp[p][s] |= dp[p - c[i]][s - c[i]] | dp[p - c[i]][s]; 最后看dp[k][i] ?= 1;

    我觉得我应该重学背包

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 505;
    bool f[M][M];
    int c[M], tp[M], tong[M], tot;
    
    
    
    int main(){
        freopen("coin.in","r",stdin);
        freopen("coin.out","w",stdout);
        int n, k, sum = 0;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++)scanf("%d", &c[i]);    
        f[0][0]=1;
        for(int i = 1; i <= n; i++)
            for(int p = k; p >= c[i]; p--)
                for(int s = k; s >= 0; s--){
                    f[p][s] |= f[p - c[i]][s];
                    if(s >= c[i])f[p][s] |= f[p - c[i]][s - c[i]];
                }
        for(int i = 0; i <= k; i++)
            if(f[k][i])tp[++tot] = i;
        printf("%d
    ", tot);
        for(int i = 1; i <= tot; i++)printf("%d ", tp[i]);
    }
    View Code
  • 相关阅读:
    965. 单值二叉树
    面试题 04.09. 二叉搜索树序列
    99. 恢复二叉搜索树
    98. 验证二叉搜索树
    centos6版本下的Python2.6升级到2.7
    操作MySQL-数据库的安装及Pycharm模块的导入
    操作微信-itchat库的安装
    2018中科大hackergame
    png图片IDAT块异常
    2018网鼎杯misc
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9481839.html
Copyright © 2020-2023  润新知