暑假第十四测

题解:

第一题: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\n", 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\n", dp[i][j], dp[i][j]);
        printf("      %d\n", i);
    }*/
        
    printf("%d\n", 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\n",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\n", tot);
    for(int i = 1; i <= tot; i++)printf("%d ", tp[i]);
}
View Code

猜你喜欢

转载自www.cnblogs.com/EdSheeran/p/9481839.html
今日推荐