1. 程式人生 > >18寒假12測

18寒假12測

數據規模 公共子序列 ans 最長上升子序列 clas 一點 can body class

Day1

題目名稱

party

array

treasure

輸入

party.in

array.in

treasure.in

輸出

party.out

array.out

treasure.out

每個測試點時限

1秒

1秒

1秒

內存限制

64MB

64MB

64MB

測試點數目

10

10

10

每個測試點分值

10

10

10

是否有部分分

題目類型

傳統

傳統

傳統

party

題目描述:

在M公司裏,每個人只有一個直屬上司(除了boss)。這個公司舉辦派對,每個人可以給派對帶來一定的歡樂值,但是每個人不能和自己的上司同時參加這個派對,求派對的最大歡樂值。

輸入:

第一行n表示公司有n個人。

第二行n個數,表示每個人的上司是誰,如果這個人的上司為0,說明這個人是boss。

第三行n個數,表示每個人的歡樂值為wi。

輸出:

一行一個數表示最大歡樂值。

樣例輸入:

6

0 1 1 1 4 4

1 1 1 1 1 1

樣例輸出:

4

解釋:2 3 5 6 同時出席。

數據規模:

對於30%的數據,n<=20。

對於100%的數據,n<= 1000000,0<=w[i]<=1000。

題解:樹形dp,dp[i][0/1]表示i號節點來不來,若父親來,兒子肯定不來,若父親不來,兒子隨便來不來;

dp[i][0] = sum( max (dp[son[i]][0], dp[son[i]][1]); dp[i][1] = sum(dp[son[i]][0]);

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1000005;
int head[maxn],tot,dp[maxn][2];
struct edge{
    int to,nxt;
}G[maxn + 100];
void add(int u,int
v){ G[++tot].nxt = head[u]; G[tot].to = v; head[u] = tot; } void dfs(int u, int f){ for(int i = head[u]; i; i = G[i].nxt){ int v = G[i].to; //if(v == f)continue; dfs(v, u); dp[u][1] += dp[v][0]; dp[u][0] += max(dp[v][0], dp[v][1]); } } int main(){ freopen("party.in","r",stdin); freopen("party.out","w",stdout); int n; scanf("%d",&n); for(int i = 1; i <= n; i++){ int fa; scanf("%d",&fa); add(fa, i); } for(int i = 1; i <= n; i++){ int w; scanf("%d",&w); dp[i][1] = w; } dfs(0, 0); cout<<dp[0][0]<<endl; }

array

題目描述:

給定兩個長度為n的排列p1和p2,求它們的最長公共子序列。

輸入:

第一行一個數n。

接下來兩個n個數分別表示p1和p2。

輸出:

一個數表示最長子序列的長度。

樣例輸入:

3

1 2 3

2 1 3

樣例輸出:

2

解釋及說明:

共有兩種方案,分別為子序列為13和子序列為23.

數據規模:

對於30%的數據,n<=2000.

對於100%的數據,n<=100000。

題解:由於是排列,所以上下元素一樣,且一個序列中無重復元素,我們就把一個序列的元素順序做一個映射,在第二個序列中作最長上升子序列

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1000005;
int d[maxn], mp[maxn], q[maxn], tail;
int main(){
    freopen("array.in","r",stdin);
    freopen("array.out","w",stdout);
    int n, a, b;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d",&a);
        mp[a] = i;
    }
    for(int j = 1; j <= n; j++){
        scanf("%d",&b);
        d[j] = mp[b];
    }
    for(int i = 1; i <= n; i++){
        if(d[i] > q[tail])q[++tail] = d[i];
        else {
            int pos = lower_bound(q + 1, q + 1 + tail, d[i]) - q;
            q[pos] = d[i];
        }
    }
    cout<<tail<<endl;
}
 

treasure

題目描述:

小a可以攻打m座城堡,攻打每個城堡有不同的寶物,但是在攻打有些城堡前,需要攻打另外的城堡。小a想知道,能獲得的最多寶物是多少?

輸入:

第一行兩個數,n,m。分別表示有n個城堡,可以攻打m個。

接下來n行每行兩個數a,b,分別表示在攻打第i個城堡前需要攻打a,攻打後獲得b的寶物。

輸出:

一行一個數ans表示可以獲得的最大寶物數量。

樣例輸入

3 2

0 1

0 2

0 3

7 4

2 2

0 1

0 4

2 1

7 1

7 6

2 2

0 0

樣例輸出:

5

13

數據規模:

對於30%的數據,n<=20,m<=20。

對於100%的數據,n<=500,m<=500,b[i]<=1000。

題解:樹形DP,這道題很像樹上染色,但不用考慮子樹和外界 聯系,要簡單一點;

dp[i][j]表示給i為根的子樹分配j次攻打機會可獲得最大的利益,答案就為dp[root][m];

由於必須打父親,才能打兒子,所以兒子可分配的機會為j-1,但0號點是我們假設的城堡,故他的子樹有j次機會,特判一下,然後做一個分組背包就好了,因為一個子樹分配的機會只能有一種方案;

抽象一下:每個子樹為一組,可供選擇的物品為min(siz[father], j), 容量為min(siz[son],j);

#include<bits/stdc++.h>
using namespace std;

const int maxn = 505;
int n,m;
int head[maxn],tot,dp[maxn][maxn],siz[maxn];
struct edge{
    int to,nxt,w;
}G[maxn + 100];
void add(int u,int v,int w){
    G[++tot].nxt = head[u];
    G[tot].to = v;
    G[tot].w = w;
    head[u] = tot;
}
void dfs(int u){
    for(int i = head[u]; i; i = G[i].nxt){
        int v = G[i].to;
        dfs(v); 
        int V = min(siz[u], m);
        int K = min(siz[v], m);
        for(int s = V; s >= 1; s--)
            for(int j = 1; j <= ( u == 0 ? min(s, K) : min(s-1, K) ); j++){
                dp[u][s] = max( dp[u][s], dp[u][s - j] + dp[v][j] + G[i].w);
            }
                
            
    }
}
void get_size(int u){
    siz[u] = 1;
    for(int i = head[u]; i; i = G[i].nxt){
        int v = G[i].to;
        get_size(v);
        siz[u] += siz[v];
    }
}


int main(){
    freopen("treasure.in","r",stdin);
    freopen("treasure.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++){
        int fa,w;
        scanf("%d%d",&fa,&w);
        add(fa, i, w);        
    }
    get_size(0);
    dfs(0);
    cout<<dp[0][m]<<endl;
}

考試突然不會分組背包了,╮(╯▽╰)╭, 一定要記得容量放外面,從大到小啊

18寒假12測