hiho编程练习赛20

模版题的世界

题目1 : 无根数变有根树

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

给定一棵包含 N 个节点的无根树,小Hi想知道如果指定其中某个节点 K 为根,那么每个节点的父节点是谁?

输入

第一行包含一个整数 N 和 K。1 ≤ N ≤ 1000, 1 ≤ K ≤ N。    

以下N-1行每行包含两个整数 a 和 b,代表ab之间存在一条边。 1 ≤ ab ≤ N。  

输入保证是一棵树。

输出

输出一行包含 N 个整数,分别代表1~N的父节点的编号。对于 K 的父节点输出0。

样例输入
5 4  
1 2  
3 1  
4 3  
5 1
样例输出
3 1 4 0 1

DFS就好啦
#include <bits/stdc++.h>
using namespace std;
#define N 1005
vector<int>G[N];
int f[N];
int n;
void dfs(int u,int fa) {
    int d=G[u].size();
    for(int i = 0;i<d;i++) {
        int v=G[u][i];
        if (v!=fa){
            dfs(v,f[v]=u);
        }
    }
}
int main() {
    scanf("%d",&n);
    int root;
    scanf("%d",&root);
    for(int i=0;i<n-1;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    f[root]=0;
    dfs(root,-1);
    printf("%d",f[1]);
    for(int i=2;i<=n;i++)
        printf(" %d",f[i]);
    return 0;
}

题目2 : SCI表示法

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

每一个正整数 N 都能表示成若干个连续正整数的和,例如10可以表示成1+2+3+4,15可以表示成4+5+6,8可以表示成8本身。我们称这种表示方法为SCI(Sum of Consecutive Integers)表示法。  

小Hi发现一个整数可能有很多种SCI表示,例如15可以表示成1+2+3+4+5,4+5+6,7+8以及15本身。小Hi想知道N的所有SCI表示中,最多能包含多少个连续正整数。例如1+2+3+4+5是15包含正整数最多的表示。

输入

第一行一个整数 T,代表测试数据的组数。  

以下 T 行每行一个正整数N。  

对于30%的数据,1 ≤ N ≤ 1000  

对于80%的数据,1 ≤ N ≤ 100000  

对于100%的数据,1 ≤ T ≤ 10,1 ≤ N ≤ 1000000000

输出

对于每组数据输出N的SCI表示最多能包含多少个整数。

样例输入
2  
15  
8
样例输出
5
1

更经典的模版题,直接枚举个数,利用奇偶性就好了,如果让求全部方案感觉还是一道不错的题
#include<bits/stdc++.h>
using namespace std;
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        int n;
        scanf("%d",&n);
        n=2*n;
        for(int z=sqrt(n+0.5);z>0;z--){
            if(n%z==0){
                if(n/z%2==0&&z%2==0)
                continue;
                else
                {printf("%d\n",z);break;}
            }
        }

    }
return 0;
}

 

 

题目4:小Hi和小Ho的对弈游戏

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi和小Ho经常一起结对编程,他们通过各种对弈游戏决定谁担任Driver谁担任Observer。

今天他们的对弈是在一棵有根树 T 上进行的。小Hi和小Ho轮流进行删除操作,其中小Hi先手。  

游戏的规则是:每次删除,小Hi或小Ho都可以选择一个非根节点,将以该节点为根的子树从 T 中删除。如果删除之后 T 只剩下一个根节点,则该次操作者胜利。  

机智的小Ho认为规则对自己不利,于是他提出了一个补充规则:在小Hi第一次删除之前,小Ho可以选择是否删除根节点。如果他选择删除根节点,则原本的有根树 T 会分裂成一个森林。之后每次删除,小Hi或小Ho都可以选择一个非根节点(不是森林中任何一棵树的根),将以该节点为根的子树删除。如果删除之后森林中只剩下根节点,则该次操作者胜利。

小Hi和小Ho都是睿智的玩家,他们总是会选择最优的方案以获得胜利。  

给定初始的有根树T,输出两个布尔值,分别代表小Ho在不删除和删除根节点时,先手的小Hi是否有必胜策略。0代表没有,1代表有。

输入

第一行包含一个整数 Q,代表测试数据的组数。1 ≤ Q ≤ 10

对于每组数据,第一行包含一个正整数 n,代表树T的节点个数。1 ≤ n ≤ 100000  

接下来n-1行,每行包含两个整数 x 和 y,代表 x 是 y 的父节点。保证输入是一棵树,节点编号1-n。  

输出

输出一个长度为2Q的01串,代表答案。

样例输入
2
5
2 5
5 4
2 3
1 2
7
4 7
2 6
1 5
3 4
1 3
1 2
样例输出
1101

树上博弈,遍历树,求异或和
#include <bits/stdc++.h>
using namespace std;
const int N=100010;
vector<int>vec[N];
int vis[N],sg[N];
void dfs(int u,int fa) {
    sg[u]=0;
    for(int i=0; i<vec[u].size(); i++) {
        if(vec[u][i]!=fa) {
            dfs(vec[u][i],u);
            sg[u]^=(1+sg[vec[u][i]]);
        }
    }
}
int main() {
    string s;
    int t;
    scanf("%d",&t);
    while(t--) {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            vec[i].clear();
            vis[i]=0;
        }
        for(int i=1; i<n; i++) {
            int a,b;
            scanf("%d%d",&a,&b);
            vec[a].push_back(b);
            vis[b]=1;
        }
        int root;
        for(int i=1; i<=n; i++)
            if(!vis[i]) {
                root=i;
                break;
            }
        dfs(root,0);
        if(sg[root])s+='1';
        else s+='0';
        int f=0;
        for(int i=0; i<vec[root].size(); i++)f^=sg[vec[root][i]];
        if(f)s+='1';
        else s+='0';
    }
    cout<<s;
    return 0;
}

 

posted @ 2017-07-30 14:34  暴力都不会的蒟蒻  阅读(449)  评论(0编辑  收藏  举报