zoukankan      html  css  js  c++  java
  • 校内的hu测(10.5)

    @liu_runda
    这次的hu测,扒的是衡水中学lrd大神出的noip模拟题

    简单来看一下吧:

    T1.简(simple)

    【题目描述】
    大道至简.这就是出题人没有写题目背景的原因.
    给出2n个数字,将它们划分成n组,每组的得分为这一组中两个数字的较小值.
    求最大得分.
    【输入格式】
    第一行一个整数n表示正整数的数目.
    接下来一行2n个空格隔开的整数a1,a2…a2n
    【输出格式】
    一行一个整数表示最大得分.
    【样例输入】
    2
    1 3 1 2
    【样例输出】
    3
    【数据范围】
    对于10%的数据:n=2
    对于另外20%的数据n<=7
    对于另外20%的数据:n<=1000
    对于另外20%的数据:ai<=100
    对于100%的数据: n<=100000,1<=ai<=10^9

    分析:
    考虑2n个数字中最小的数字,
    和它一组的数字产生的价值必然等于这个最小的数字
    因此让第2小的数字和它一组是最优的
    排序后从小到大依次分组即可

    tip

    开ll

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    
    using namespace std;
    
    int n;
    int a[200010];
    
    int main()
    {
        freopen("simple.in","r",stdin);  
        freopen("simple.out","w",stdout);
        scanf("%d",&n);
        for (int i=1;i<=2*n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n+n);
        ll ans=0;
        for (int i=1;i<=n*2;i+=2)
            ans+=(ll)a[i];
        printf("%lld",ans);
        return 0;
    }

    T2.单(single)

    【题目描述】
    单车联通大街小巷.这就是出题人没有写题目背景的原因.
    对于一棵树,认为每条边长度为1,每个点有一个权值a[i].dis(u,v)为点u到v的最短路径的边数.dis(u,u)=0.对每个点求出一个重要程度.点x的重要程度b[x]定义为其他点到这个点的距离乘上对应的点权再求和. 即:b[x]=a[1]*dis(1,x)+a[2]*dis(2,x)+….+a[n]*dis(n,x)
    现在有很多树和对应的a数组,并求出了b数组.不幸的是,记录变得模糊不清了.幸运的是,树的形态完好地保存了下来,a数组和b数组至少有一个是完好无损的,但另一个数组完全看不清了.
    希望你求出受损的数组.多组数据.
    【输入格式】
    第一行输入一个T,表示数据组数。接下来T组数据。
    每组数据的第1行1个整数n表示树的点数.节点从1到n编号.
    接下来n-1行每行两个整数u,v表示u和v之间有一条边.
    接下来一行一个整数t,表示接下来数组的类型。
    t=0则下一行是a数组,t=1则下一行是b数组。
    接下来一行n个整数,表示保存完好的那个数组,第i个数表示a[i]或b[i]。
    【输出格式】
    T行,每组数据输出一行表示对应的a数组或b数组,数组的相邻元素用一个空格隔开。忽略行末空格和行尾回车.
    【样例输入】
    2
    2
    1 2
    1
    17 31
    2
    1 2
    0
    31 17
    【样例输出】
    31 17
    17 31
    【数据范围】
    对于100%的数据,T=5,2<=n<=100000,1<=u,v<=n,保证给出的n-1条边形成一棵树
    对于100%的数据,t=0或t=1,1<=a[i]<=100,1<=b[i]<=10^9,t=1时保证给出的b数组对应唯一的一个a数组。
    对于100%的数据,单个输入文件不会包含超过2000000个整数,这段话可以理解为,你不必考虑输入输出对程序运行时间的影响。
    对于100%的数据,保证答案不会超过int能表示的范围
    接下来的表格中描述了每个测试点的具体特征。每个测试点的5组数据均符合表格中对应的特征。

    测试点编号 n 特殊限制
    1 <=1000 均有t=0
    2 <=5 均有t=1,答案中a[i]<=20
    3 <=100 均有t=1
    4 <=100 均有t=1
    5 <=30000 所有边满足v=u+1
    6 <=10^5 均有t=0
    7 <=10^5 均有t=0
    8 <=10^5 无特殊限制
    9 <=10^5 无特殊限制
    10 <=10^5 无特殊限制

    分析:
    先说一下我自己yy的写法
    受到1002T2的启发
    我发现b可以两遍dfs算出(树形dp)
    sum:子树中Σai
    zz:只在子树中计算的b
    所以每个点的b可以从根向叶子推出
    这里写图片描述

    void dfs(int now,int f)
    {
        deep[now]=deep[f]+1;
        sum[now]=a[now];
        for (int i=st[now];i;i=way[i].nxt)
            if (way[i].y!=f)
            {
                dfs(way[i].y,now);
                zz[now]+=zz[way[i].y]+sum[way[i].y];   //子树中的b 
                sum[now]+=sum[way[i].y];
            }    
    }
    
    void js(int now,int fa)
    {
        if (fa==0)
        {
            b[now]=zz[now]; 
        }
        else
        {
            int ff=b[fa];
            ff-=zz[now]; ff-=sum[now];
            ff+=(sum[1]-sum[now]);
            b[now]=ff+zz[now];
        } 
        for (int i=st[now];i;i=way[i].nxt)
            if (way[i].y!=fa)
                js(way[i].y,now);
    }

    所以稳妥30

    现在的问题主要在t=1上:

    我们遵从由浅入深的原则
    先看链上的问题
    对于测试点5,树退化为1条链。这个测试点的作用主要在于启发选手想到正解的思路。

    考虑t=1的情况
    我们知道suf(2)+suf(3)+…+suf(n)的值(即b[1])
    知道pre(1) + suf(3) + suf(4) +…+suf(n)的值(即b[2])
    知道pre(1)+pre(2)+suf(4)+…+suf(n)的值(即b[3])
    注意到这些式子有很多项是一样的
    考虑作差,可以得到下面的式子:
    b[2]-b[1]=pre(1)-suf(2)
    b[3]-b[2]=pre(2)-suf(3)
    …..
    b[i+1]-b[i]=pre(i)-suf(i+1)
    这些式子是有实际意义的,考虑从b[1]变到b[2]时答案的变化量
    变化的就是1和2之间连边的贡献

    同时,记SUM=a[1]+a[2]+…+a[n-1]+a[n],
    显然pre(i)+suf(i+1)=SUM
    因此pre(i)=SUM-suf(i+1)
    将上面式子中所有pre换成suf,
    我们就知道了SUM-2*suf(2) ,SUM-2*suf(3)…SUM-2*suf(n)的取值

    但是这些式子还不够
    b[1]=suf(2)+suf(3)+suf(4)+… +suf(n)
    我们发现suf(2)到suf(n)都恰好出现了一次
    而之前得到了n-1个形如SUM-2*suf(i)的式子,
    将这n-1个式子相加
    suf(2),suf(3)…suf(n)前面的系数都是2,SUM的系数为(n-1)
    那么把这个式子加上2*b[1]=2*(suf(2)+suf(3)+…+suf(n))
    就得到了(n-1)*SUM,
    将求得的SUM代入之前的n-1个式子可以得到suf(2),suf(3),suf(4)……suf(n)
    差分一下即可得到a数组.
    时间复杂度O(n),可以通过第5个测试点
    推出这个做法,树上的做法也就不难想了

    t=1的时候,我们先随便找一个点为根建树,
    将有边直接相连的两个点的b[i]作差
    设x的父亲为fa[x],
    以x为根的子树中所有a[i]之和为sum(x),
    SUM=a[1]+a[2]+…+a[n-1]+a[n],
    那么b[x]-b[fa[x]]=(SUM-sum(x))-sum(x).
    同链的情况一样,得到n-1个式子,
    将树根的b[i]也列出式子,
    b[root]=sum(2)+sum(2)+..+sum(n)
    可以求出全部a[i]之和,
    然后就可以根据之前的式子推出所有的a[i]

    T3.题(problem)

    【题目描述】
    出个题就好了.这就是出题人没有写题目背景的原因.
    你在平面直角坐标系上.
    你一开始位于(0,0).
    每次可以在上/下/左/右四个方向中选一个走一步.
    即:从(x,y)走到(x,y+1),(x,y-1),(x-1,y),(x+1,y)四个位置中的其中一个.
    允许你走的步数已经确定为n.现在你想走n步之后回到(0,0).但这太简单了.你希望知道有多少种不同的方案能够使你在n步之后回到(0,0).当且仅当两种方案至少有一步走的方向不同,这两种方案被认为是不同的.
    答案可能很大所以只需要输出答案对10^9+7取模后的结果.(10^9+7=1000000007,1和7之间有8个0)
    这还是太简单了,所以你给能够到达的格点加上了一些限制.一共有三种限制,加上没有限制的情况,一共有四种情况,用0,1,2,3标号:
    0.没有任何限制,可以到达坐标系上所有的点,即能到达的点集为{(x,y)|x,y为整数}
    1.只允许到达x轴非负半轴上的点.即能到达的点集为{(x,y)|x为非负数,y=0}
    2.只允许到达坐标轴上的点.即能到达的点集为{(x,y)|x=0或y=0}
    3.只允许到达x轴非负半轴上的点,y轴非负半轴上的点以及第1象限的点.即能到达的点集为{(x,y)|x>=0,y>=0}
    【输入格式】
    一行两个整数(空格隔开)n和typ,分别表示你必须恰好走的步数和限制的种类.typ的含义见【题目描述】.
    【输出格式】
    一行一个整数ans,表示不同的方案数对10^9+7取模后的结果.
    【样例输入0】
    100 0
    【样例输出0】
    383726909
    【样例输入1】
    100 1
    【样例输出1】
    265470434
    【样例输入2】
    100 2
    【样例输出2】
    376611634
    【样例输入3】
    100 3
    【样例输出3】
    627595255
    【数据范围】
    10%的数据,typ=0,n<=100
    10%的数据,typ=0,n<=1000
    5%的数据, typ=0,n<=100000
    10%的数据,typ=1,n<=100
    10%的数据,typ=1,n<=1000
    5%的数据, typ=1,n<=100000
    10%的数据,typ=2,n<=100
    15%的数据,typ=2,n<=1000
    10%的数据,typ=3,n<=100
    10%的数据,typ=3,n<=1000
    5%的数据, typ=3,n<=100000
    以上11部分数据没有交集.
    100%的数据,保证n为偶数,2<=n<=100000,0<=typ<=3.

    分析:
    考场上强行dp+滚动数组优化空间
    卡过65
    正解:卡特兰数

    int doit1()
    {
        int i,j,k;
        int now=0;
        f[0][n/2+1][n/2+1]=1;
        for (i=1;i<=n;i++)
        {
            now^=1;
            memset(f[now],0,sizeof(f[now]));
            for (j=0;j<=n+1;j++)
                for (k=0;k<=n+1;k++)
                {
                    if (j) f[now][j][k]+=f[now^1][j-1][k],f[now][j][k]%=mod;
                    if (k) f[now][j][k]+=f[now^1][j][k-1],f[now][j][k]%=mod;
                    f[now][j][k]+=f[now^1][j+1][k],f[now][j][k]%=mod;
                    f[now][j][k]+=f[now^1][j][k+1],f[now][j][k]%=mod;
                }
        }
        return f[now][n/2+1][n/2+1]%mod;
    }
    
    int doit2()
    {
        int i,j,k;
        int now=0;
        f[0][n/2+1][n/2+1]=1;
        for (i=1;i<=n;i++)
        {
            now^=1;
            memset(f[now],0,sizeof(f[now]));
            for (j=0;j<=n+1;j++)
            {
                if (j) f[now][j][n/2+1]+=f[now^1][j-1][n/2+1],f[now][j][n/2+1]%=mod;
                f[now][j][n/2+1]+=f[now^1][j+1][n/2+1],f[now][j][n/2+1]%=mod;
            }
            for (k=0;k<=n+1;k++)
            {
                if (k) f[now][n/2+1][k]+=f[now^1][n/2+1][k-1],f[now][n/2+1][k]%=mod;
                f[now][n/2+1][k]+=f[now^1][n/2+1][k+1],f[now][n/2+1][k]%=mod;
            }
        }
        return f[now][n/2+1][n/2+1]%mod;
    }
    
    int doit3()
    {
        int i,j,k;
        int now=0;
        f[0][0][0]=1;
        for (i=1;i<=n;i++)
        {
            now^=1;
            memset(f[now],0,sizeof(f[now]));
            for (j=0;j<=n+1;j++)
                for (k=0;k<=n+1;k++)
                {
                    if (j) f[now][j][k]+=f[now^1][j-1][k],f[now][j][k]%=mod;
                    if (k) f[now][j][k]+=f[now^1][j][k-1],f[now][j][k]%=mod;
                    f[now][j][k]+=f[now^1][j+1][k],f[now][j][k]%=mod;
                    f[now][j][k]+=f[now^1][j][k+1],f[now][j][k]%=mod;
                }
        }
        return f[now][0][0]%mod;
    }
    
    int solve()
    {
        int i,j,k;
        int now=0;
        ff[0][0]=1;
        for (i=1;i<=n;i++)
        {
            now^=1;
            memset(ff[now],0,sizeof(ff[now]));
            for (j=0;j<=n+1;j++)
            {
                if (j) ff[now][j]+=ff[now^1][j-1],ff[now][j]%=mod;
                ff[now][j]+=ff[now^1][j+1],ff[now][j]%=mod;
            }
        }
        return ff[now][0]%mod;
    }

    T3详尽题解

  • 相关阅读:
    CoreJava逻辑思维-顺时针打印自定义矩阵
    微信公众号开发引言
    .Net自动更新程序GeneralUpdate,适用于wpf,winfrom,控制台应用
    .net技术栈转型心路历程分享
    TCP/IP网络编程之数据包协议
    TCP/IP网络编程之字节序和网络字节序
    TCP/IP网络编程之socket交互流程
    Linux入门笔记
    WPF新手快速入门系列 3.MVVM
    WPF新手快速入门系列 2.绑定
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673099.html
Copyright © 2011-2022 走看看