• 9.2noip模拟试题


     

    题目名称

    改造二叉树

    数字对

    交换

    英文名称

    binary

    pair

    swap

    输入文件名

    binary.in

    pair.in

    swap.in

    输出文件名

    binary.out

    pair.out

    swap.out

    时间限制

    1s

    2s

    1s

    空间限制

    256M

    256M

    256M

    测试点数目

    20

    20

    10

    测试点分值

    5

    5

    10

    是否有部分分

    题目类型

    传统

    传统

    传统

    是否有SPJ

    1.改造二叉树

    【题目描述】

    小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树。通常子结点被称作“左孩子”和“右孩子”。二叉树被用作二叉搜索树和二叉堆。随后他又和他人讨论起了二叉搜索树。

    什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设key[p]表示结点p上的数值。对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch];若其存在右孩子rch,则key[p]<key[rch];注意,本题中的二叉搜索树应满足对于所有结点,其左子树中的key小于当前结点的key,其右子树中的key大于当前结点的key。

    小Y与他人讨论的内容则是,现在给定一棵二叉树,可以任意修改结点的数值。修改一个结点的数值算作一次修改,且这个结点不能再被修改。若要将其变成一棵二叉搜索树,且任意时刻结点的数值必须是整数(可以是负整数或0),所要的最少修改次数。

    相信这一定难不倒你!请帮助小Y解决这个问题吧。

    【输入格式】

           第一行一个正整数n表示二叉树结点数。结点从1~n进行编号。

    第二行n个正整数用空格分隔开,第i个数ai表示结点i的原始数值。

    此后n - 1行每行两个非负整数fa, ch,第i + 2行描述结点i + 1的父亲编号fa,以及父子关系ch,(ch = 0 表示i + 1为左儿子,ch = 1表示i + 1为右儿子)。

    结点1一定是二叉树的根。

     

    【输出格式】

           仅一行包含一个整数,表示最少的修改次数。

     

    【样例输入】

    3

    2 2 2

    1 0

    1 1

     

    【样例输出】

    2

     

    【数据范围】

    20 % :n <= 10 , ai <= 100.

    40 % :n <= 100 , ai <= 200

    60 % :n <= 2000 .

    100 % :n <= 10 ^ 5 ,  ai < 2 ^ 31.

     

    /*
    想到了中序遍历然后做lis 
    但是只25分 有一种情况是
    2 5 3 4
    这样lis是3 按说改一个5就行
    但是题目限制了改成整数 2 3之间不能填了
    这就wawawawawa~
    这里学习了一种常见的将严格上升的的序列等价转化成不降的序列的方法
     a1 a2 a3 -> a1-1 a2-2 a3-3
    这样再做不降的lis就好了 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define maxn 200010
    using namespace std;
    int n,a[maxn],b[maxn],len,lc[maxn],rc[maxn],c[maxn],r;
    void Dfs(int x){
        if(lc[x])Dfs(lc[x]);
        b[++len]=x;
        if(rc[x])Dfs(rc[x]);
    }
    void LIS(){
        for(int i=1;i<=len;i++){
            int x=a[b[i]];x-=i;
            if(x>=c[r]){
                c[++r]=x;
                continue;
            }
            int p=upper_bound(c+1,c+1+r,x)-c;
            c[p]=x;
        }
    } 
    int main()
    {
        freopen("binary.in","r",stdin);
        freopen("binary.out","w",stdout); 
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int x,y;
        for(int i=2;i<=n;i++){
            scanf("%d%d",&x,&y);
            if(y==0)lc[x]=i;
            if(y==1)rc[x]=i;
        }
        Dfs(1);
        LIS();
        printf("%d
    ",len-r);
        return 0;
    }
    View Code

     

    2.数字对

    【题目描述】

    小H是个善于思考的学生,现在她又在思考一个有关序列的问题。

    她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。

    这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。

    小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。

    【输入格式】

           第一行,一个整数n.

           第二行,n个整数,代表ai.

    【输出格式】

           第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。

    第二行num个整数,按升序输出每个价值最大的特殊区间的L.

    【样例输入1】

    5

    4 6 9 3 6

    【样例输出1】

    1 3

    2

    【样例输入2】

    5

    2 3 5 7 11

    【样例输出2】

    5 0

    1 2 3 4 5

    【数据范围】

        30%: 1 <= n <= 30 , 1 <= ai <= 32.

        60%: 1 <= n <= 3000 , 1 <= ai <= 1024.

        80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.

       100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.

     暴力:

    /*
    n*n暴力 枚举ak 然后左右拓展
    虽然是暴力 但是跑的飞快~~
    注意输出的是不一样的区间.... 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 500010
    using namespace std;
    int n,a[maxn],mxx,mxl,sum,Ans[maxn];
    struct node{
        int len,L;
    }ans[maxn];
    int init(){
        int x=0;char s=getchar();
        while(s<'0'||s>'9')s=getchar();
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x;
    }
    int cmp(const node &x,const node &y){
        if(x.len==y.len)return x.L<y.L;
        return x.len>y.len;
    }
    int Gcd(int a,int b){
        return !b?a:Gcd(b,a%b);
    }
    int main()
    {
        freopen("pair.in","r",stdin);
        freopen("pair.out","w",stdout);
        n=init();
        for(int i=1;i<=n;i++)
            a[i]=init();
        for(int k=1;k<=n;k++){
            int li=k,ri=k,gcd=a[k];
            for(int i=k+1;i<=n;i++)
                if(Gcd(gcd,a[i])!=gcd)break;
                else ri++;
            for(int i=k-1;i>=1;i--)
                if(Gcd(gcd,a[i])!=gcd)break;
                else li--;
            ans[k].len=ri-li;ans[k].L=li;
        }
        sort(ans+1,ans+1+n,cmp);
        mxx=ans[1].len;mxl=ans[1].L;
        Ans[++sum]=mxl;
        for(int k=2;k<=n;k++)
            if(ans[k].len!=mxx)break;
            else if(ans[k].L!=mxl){
                Ans[++sum]=ans[k].L;
                mxl=ans[k].L;
            }
        printf("%d %d
    ",sum,mxx);
        for(int i=1;i<=sum;i++)
            printf("%d ",Ans[i]);
        return 0;
    }
    View Code

    ST表:

    /*
    nlogn做法
    同样的枚举ak 左右拓展的时候二分来搞
    这里恰好有单调性~
    ST表预处理一下 O(1)查询 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 500010
    using namespace std;
    int n,a[maxn],f[maxn][20],p[maxn],mxx,mxl,sum,Ans[maxn];
    struct node{
        int len,L;
    }ans[maxn];
    int init(){
        int x=0;char s=getchar();
        while(s<'0'||s>'9')s=getchar();
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x;
    }
    int cmp(const node &x,const node &y){
        if(x.len==y.len)return x.L<y.L;
        return x.len>y.len;
    }
    int Gcd(int a,int b){
        return !b?a:Gcd(b,a%b);
    }
    int Get_pow(int x){
        for(int i=0;;i++)
            if((1<<i)>x)return i-1;
    }
    void Get_ST(){
        for(int i=1;i<=n;i++)
            f[i][0]=a[i];
        for(int j=1;j<=18;j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                f[i][j]=Gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        for(int i=1;i<=n;i++)
            p[i]=Get_pow(i);
    }
    int find(int l,int r){
        if(l>r)return 0;
        int len=p[r-l+1];
        return Gcd(f[l][len],f[r-(1<<len)+1][len]);
    }
    int main()
    {
        freopen("pair.in","r",stdin);
        freopen("pair.out","w",stdout);
        n=init();
        for(int i=1;i<=n;i++)
            a[i]=init();
        Get_ST();
        for(int k=1;k<=n;k++){
            int li=k,ri=k,gcd=a[k],l,r;
            l=0;r=n-k+1;
            while(l<=r){
                int mid=l+r>>1;
                int x=find(k,k+mid-1);
                if(x==gcd){
                    ri=k+mid-1;l=mid+1;
                }
                else r=mid-1;
            }
            l=0;r=k;
            while(l<=r){
                int mid=l+r>>1;
                int x=find(k-mid+1,k);
                if(x==gcd){
                    li=k-mid+1;l=mid+1;
                }
                else r=mid-1;
            }
            ans[k].len=ri-li;ans[k].L=li;
        }
        sort(ans+1,ans+1+n,cmp);
        mxx=ans[1].len;mxl=ans[1].L;
        Ans[++sum]=mxl;
        for(int k=2;k<=n;k++)
            if(ans[k].len!=mxx)break;
            else if(ans[k].L!=mxl){
                Ans[++sum]=ans[k].L;
                mxl=ans[k].L;
            }
        printf("%d %d
    ",sum,mxx);
        for(int i=1;i<=sum;i++)
            printf("%d ",Ans[i]);
        return 0;
    }
    View Code

    3.交换

    【题目描述】

           给定一个{0, 1, 2, 3, … , n - 1}的排列 p。一个{0, 1, 2 , … , n - 2}的排列q被认为是优美的排列,当且仅当q满足下列条件:

           对排列s = {0, 1, 2, 3, ..., n - 1}进行n – 1次交换。

    1. 交换s[q0],s[q0 + 1]
    2. 交换s[q1],s[q1 + 1]

    最后能使得排列s = p.

    问有多少个优美的排列,答案对10^9+7取模。

    【输入格式】

    第一行一个正整数n.

    第二行n个整数代表排列p.

    【输出格式】

           仅一行表示答案。

    【样例输入】

    3

    1 2 0

    【样例输出】

    1

    【样例解释】

    q = {0,1} {0,1,2} ->{1,0,2} -> {1, 2, 0}

    q = {1,0} {0,1,2} ->{0,2,1} -> {2, 0, 1}

    【数据范围】

    30%:  n <= 10

    100%:  n <= 50

     暴力:

    /*直接暴力n!*/
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 51
    using namespace std;
    int n,p[maxn],q[maxn],s[maxn],ans;
    int main()
    {
        freopen("swap.in","r",stdin);
        freopen("swap.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<n;i++)q[i]=i;
        for(int i=1;i<=n;i++){
            int x;scanf("%d",&x);
            p[i]=x+1;
        }
        do{
            for(int i=1;i<=n;i++)s[i]=i;
            for(int i=1;i<n;i++)swap(s[q[i]],s[q[i]+1]);
            int falg=0;
            for(int i=1;i<=n;i++)
                if(s[i]!=p[i]){
                    falg=1;break;
                }
            if(falg==0)ans++;
        }while(next_permutation(q+1,q+n));
        printf("%d
    ",ans);
    }
    View Code
  • 相关阅读:
    mysql 查看删除触发器等操作
    gtid同步异常处理
    使用MongoDB数据库(2)(三十六)
    使用MongoDB数据库(1)(三十五)
    使用Redis数据库(2)(三十四)
    使用Redis数据库(1)(三十三)
    多数据源配置与使用(2)(三十二)
    多数据源配置与使用(1)(三十二)
    使用Spring-data-jpa(2)(三十一)
    使用Spring-data-jpa(1)(三十)
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/5832924.html
Copyright © 2020-2023  润新知