首页 > 其他 > 详细

18寒假12测

时间:2018-03-03 20:24:27      阅读:194      评论:0      收藏:0      [点我收藏+]

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测

原文:https://www.cnblogs.com/EdSheeran/p/8502658.html

踩
(0)
赞
(0)
   
举报
评论 一句话评论(0)
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!