zoukankan      html  css  js  c++  java
  • noip2015提高组day2解题报告

    1、跳石头

    题目描述

    一年一度的“跳石头”比赛又要开始了!

    这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

    为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M块岩石(不能移走起点和终点的岩石)。

    输入格式

    输入文件第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L1 且 NM0

    接下来 N行,每行一个整数,第 i 行的整数 Di0<Di<L, 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

    输出格式

    输出文件只包含一个整数,即最短跳跃距离的最大值。

    样例一

    input

    25 5 2
    2
    11
    14
    17
    21
    

    output

    4
    

    explanation

    将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

    限制与约定

    测试点编号n,m的规模L的规模
    1 n,m10
    L10^9
    2
    3 n,m100
    4
    5
    6 n,m50000
    7
    8
    9
    10

    时间限制:1s

    空间限制:128MB

    /*

    显然,二分答案

    */

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int l,n,m;
    int a[50005];
    int L;
    int check(int x)
    {
        int last = 0;//last为前一个石头到指向石头的距离 
        int ans = 0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]-last<x) //如果第i个石头到前一个石头的距离小于假设的答案 
                ans++;  //该石头可以搬走 
            else//如果大于(即满足条件) 
                last = a[i]; //则保留该石头,并将last赋值为该石头到原点的距离以便计算下一个石头到它的距离 
        }
        if(ans>m)return 0;
        return 1;
    }
    int main()
    {
        scanf("%d%d%d",&L,&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        a[n+1]=L;n++;//我们假设在终点处有第n+1个石头,则他到起点的距离为L 
        int l=0,r=L;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid))l=mid+1;//说明二分结果小了,要向右二分
            else r=mid-1;//说明结果大了,要向左二分
        }
        printf("%d
    ",l-1);
    }

    2、子串

    题目描述

    有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。

    输入输出格式

    输入格式:

    输入文件名为 substring.in。

    第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述所提到的 k,每两个整数之间用一个空格隔开。 第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。

    输出格式:

    输出文件名为 substring.out。 输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求[b]输出答案对 1,000,000,007 取模的结果。[/b]

    输入输出样例

    输入样例#1:
    6 3 1 
    aabaab 
    aab
    输出样例#1:
    2
    输入样例#2:
    6 3 2 
    aabaab 
    aab
    输出样例#2:
    7
    输入样例#3:
    6 3 3 
    aabaab 
    aab
    输出样例#3:
    7

    说明

    对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;

    对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2; 对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m; 对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m; 对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m; 对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。

     【题目分析】转自:https://blog.sengxian.com/solutions/noip-2015-day2#toc_6

        dp题

    设 f[i][j][k]f[i][j][k] 为串 AA 匹配到第 i1i−1 个位置(位置从 00 开始),串 BB 匹配到 j1j−1 个位置,而且恰好选串 AA 的 i1i−1 号字符的方案总数。
    设 s[i][j][k]s[i][j][k] 为串 AA 匹配到第 i1i−1 个位置(位置从 00 开始),串 BB 匹配到 j1j−1 个位置,的方案总数。可以知道 s[m][n][k]s[m][n][k]就是要求的答案。
    考虑边界,空空相对,00 组有一种方法,所以有 s[i][0][0]=1s[i][0][0]=1。
    接下来考虑状态转移方程:s[i][j][k]s[i][j][k] 是很容易求出来的。
    s[i][j][k]=s[i1][j][k]+f[i][j][k]s[i][j][k]=s[i−1][j][k]+f[i][j][k]
    很好理解,s[i][j][k]s[i][j][k] 的方案数目就等于上一个阶段(串 AA 还没有使用第 i1i−1 个位置) 的方案数目,加上串 AA 使用第 i1i−1 个位置的方案总数。
    怎么求解 f[i][j][k]f[i][j][k] 呢?这里运用了类似的最长公共子序列的思想。
    如果 A[i1]=B[j1]A[i−1]=B[j−1],那么串 AA 的 i1i−1 位置就可以跟 i2i−2 位置合成一组(如果可能的话),这时组数不变;也可以不跟 i2i−2 位置合成一组,自成一组,这时组数+1。所以
    f[i][j][k]=f[i1][j1][k]+s[i1][j1][k1](A[i1]=B[j1])如果 f[i][j][k]=f[i−1][j−1][k]+s[i−1][j−1][k−1](A[i−1]=B[j−1])
    A[i1]B[j1] 呢?根据定义,A[i−1]≠B[j−1]f[i][j][k] 要恰好选串 f[i][j][k]A 的 Ai1 号字符,现在选不了,自然为 i−10。所以0
    f[i][j][k]=0综上所述,得到完整的状态转移方程:f[i][j][k]=0

    f[i][j][k]={f[i1][j1][k]+s[i1][j1][k1](A[i1]=B[j1])0(A[i1]B[j1])s[i][j][k]=s[i1][j][k]+f[i][j][k]最后数组压到二维的就可以省空间了。f[i][j][k]={f[i−1][j−1][k]+s[i−1][j−1][k−1](A[i−1]=B[j−1])0(A[i−1]≠B[j−1])s[i][j][k]=s[i−1][j][k]+f[i][j][k]

        

    3、运输计划

    题目背景

    公元 2044 年,人类进入了宇宙纪元。

    题目描述

    L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条

    航道连通了 L 国的所有星球。

    小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

    流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

    为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

    在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

    如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?

    输入输出格式

    输入格式:

    输入文件名为 transport.in。

    第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的

    数量,星球从 1 到 n 编号。

    接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第

    i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。 接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个

    运输计划是从 uj 号星球飞往 vj 号星球。

    输出格式:

    输出文件名为 transport.out。

    共 1 行,包含 1 个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

    输入输出样例

    输入样例#1:
    6 3 
    1 2 3 
    1 6 4 
    3 1 7 
    4 3 6 
    3 5 5 
    3 6 
    2 5 
    4 5
    输出样例#1:
    11

    说明

    所有测试数据的范围和特点如下表所示

    请注意常数因子带来的程序效率上的影响。

    这道题我并不会,华东浮山的代码,你们随便感受下,我蒟蒻 我走了

    #include<cstdio>
    #include<cstring>
    #include<iostream> 
    #define N 300010
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    struct edge{
        int next,data,d;
    }e[N*2];
    struct qedge{
        int next,d,lca,now;
    }qe[N*2];
    int n,m,i,j,q[N],efree,x,y,z,l,r,w,dfsx[N],mid,d[N],ans,ff[N],s[N],f[N],qq[N],qefree;
    int max(int x,int y){return x>y?x:y;}
    void add(int x,int y,int z){
        e[++efree].d=y;
        e[efree].data=z;
        e[efree].next=q[x];
        q[x]=efree;
    }
    void qadd(int x,int y){
        qe[++qefree].d=y;
        qe[qefree].now=x;
        qe[qefree].next=qq[x];
        qq[x]=qefree;
    }
    void dfs1(int x,int y,int z){
        ff[x]=y;
        d[x]=z;
        for(int i=q[x];i;i=e[i].next)
            if(e[i].d!=y)dfs1(e[i].d,x,z+e[i].data);
        dfsx[++w]=x;
    }
    int gf(int x){return f[x]==x?x:f[x]=gf(f[x]);}
    void tarjan(int x){
        f[x]=x;
        for(int i=q[x];i;i=e[i].next)
            if(e[i].d!=ff[x]){
                tarjan(e[i].d);
                f[e[i].d]=x;
            }
        for(int i=qq[x];i;i=qe[i].next)
            if(f[qe[i].d])qe[i].lca=gf(qe[i].d);
    }
    bool pd(int x){
        int i,ans=0,total=0,now=0;
        memset(s,0,sizeof(s));
        for(i=1;i<=qefree;i+=2){
            qe[i].lca=max(qe[i].lca,qe[i+1].lca);
            if(d[qe[i].now]+d[qe[i].d]-2*d[qe[i].lca]>x){
                total++;
                s[qe[i].now]++;
                s[qe[i].d]++;
                s[qe[i].lca]-=2;
                now=max(now,d[qe[i].now]+d[qe[i].d]-2*d[qe[i].lca]-x);
            }
        }
        for(i=1;i<=n;i++)s[ff[dfsx[i]]]+=s[dfsx[i]];
        for(i=1;i<=n;i++)
            if(s[i]==total)ans=max(ans,d[i]-d[ff[i]]);
        return ans>=now;
    }
    int main(){
       n=read();m=read();
        for(i=1;i<n;i++){
            x=read();y=read();z=read();
            add(x,y,z),add(y,x,z);
            r+=z;
        }
        for(i=1;i<=m;i++){
            x=read();y=read();
            qadd(x,y),qadd(y,x);
        }
        dfs1(1,0,0);
        tarjan(1);
        while(l<=r){
            mid=(l+r)>>1;
            if(pd(mid))ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
    }
  • 相关阅读:
    zju 2886
    zju 2478
    UVA350-水题
    UVA699-落叶-二叉树
    UVA327
    UVA548
    java环境变量
    synchronized关键字
    uva297
    UVA196
  • 原文地址:https://www.cnblogs.com/xiaoningmeng/p/5695653.html
Copyright © 2011-2022 走看看