zoukankan      html  css  js  c++  java
  • 【NOIP2015】提高day2解题报告

    题目:

    P1981跳石头

    描述

    一年一度的“跳石头”比赛又要开始了!
    这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终 点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
    为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳 跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能 移走起点和终点的岩石)。

    格式

    输入格式

    输入第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终 点之间的岩石数,以及组委会至多移走的岩石数。
    接下来 N 行,每行一个整数,第 i 行的整数 DiDi0<Di<L0<Di<L)表示第 ii 块岩石与 起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同 一个位置。

    输出格式

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

    样例1

    样例输入1[复制]

     
    25 5 2
    2
    11
    14
    17
    21

    样例输出1[复制]

     
    4

    限制

    对于20%的数据,0MN100≤M≤N≤10
    对于50%的数据,0MN1000≤M≤N≤100
    对于100%的数据,0MN500000≤M≤N≤500001L10000000001≤L≤1000000000

    提示

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


    P1982子串

    描述

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

    格式

    输入格式

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

    输出格式

    输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输 出答案对 1,000,000,007 取模的结果。

    样例1

    样例输入1[复制]

     
    6 3 1
    aabaab
    aab

    样例输出1[复制]

     
    2

    样例2

    样例输入2[复制]

     
    6 3 2
    aabaab
    aab

    样例输出2[复制]

     
    7

    样例3

    样例输入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。

    提示

    样例 1:aab aab / aab aab
    样例 2:a ab aab / a aba ab / a a ba ab / aab a ab
    aa b aab / aa baa b / aab aa b
    样例 3:a a b aab / a a baa b / a ab a a b / a aba a b
    a b a a b / a a ba a b / aab a a b


    P1983运输计划

    描述

    公元 2044 年,人类进入了宇宙纪元。L 国有 nn 个星球,还有 n1n−1 条双向航道,每条航道建立在两个星球之间,这 n1n−1 条 航道连通了 L 国的所有星球。

    小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物 流飞船需要从 uiui 号星球沿最快的宇航路径飞行到 vivi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 tjtj,并且任意两艘飞船之间不会产生任何干扰。

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

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

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

    格式

    输入格式

    第一行包括两个正整数 nnmm,表示 L 国中星球的数量及小 P 公司预接的运输计划的 数量,星球从 11到 nn 编号。

    接下来 n1n−1 行描述航道的建设情况,其中第 ii 行包含三个整数 aiaibibi 和 titi,表示第 ii 条双向航道修建在 aiai 与 bibi 两个星球之间,任意飞船驶过它所花费的时间为 titi

    接下来 mm 行描述运输计划的情况,其中第 jj 行包含两个正整数 ujuj 和 vjvj,表示第 jj 个 运输计划是从ujuj 号星球飞往 vjvj 号星球。

    输出格式

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

    样例1

    样例输入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

    限制

    一共有20组数据。

    其中n的取值依次为:100,100,100,2000,1000,2000,3000,1000,2000,3000,80000,100000,70000,80000,90000,100000,80000,90000,100000,300000。

    其中m的取值依次为:1,100,100,1,1000,2000,3000,1000,2000,3000,1,1,70000,80000,90000,100000,80000,90000,100000,300000。

    其中第2,5,6,7,13,14,15,16组数据满足:第 i 条航道连接 i 号星球与 i+1 号星球。

    提示

    输入输出样例 1 说明。

      将第 1 条航道改造成虫洞:则三个计划耗时分别为:11、12、11,故需要花费的时 间为 12。
      将第 2 条航道改造成虫洞:则三个计划耗时分别为:7、15、11,故需要花费的时 间为 15。
      将第 3 条航道改造成虫洞:则三个计划耗时分别为:4、8、11,故需要花费的时间 为 11。
      将第 4 条航道改造成虫洞:则三个计划耗时分别为:11、15、5,故需要花费的时 间为 15。
      将第 5 条航道改造成虫洞:则三个计划耗时分别为:11、10、6,故需要花费的时 间为 11。
      故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花 费的时间为 11。


    解题报告:

       第一题:先开始的时候,看见的时候觉得是贪心,然后又觉得有反例,就没敢写,然后就开始暴搜,只有10分。。

          这里有一个套路,就是在最小中求最大,或者最大中最小,就想到二分。一定要形成条件反射,想不到方法,就试一试二分可不可以解决。这里因为总长度是确定的,所以可以二分答案,然后判断不满足此长度的点(即与前一个点的距离小于该长度,这里有一个更新last,只有当删了一个节点时才更新,所以代码里是有一个else)如果个数大于m,就取左区间。注意二分的模板和 判重 。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define maxn 50005
     6 using namespace std;
     7 int n,m,l,li,ri,ans;
     8 int a[maxn];
     9 bool pd(int x)
    10 {
    11     int last=0,sum=0;
    12     for (int i=1;i<=n+1;i++)// n+1
    13     {
    14         if (a[i]-last<x) sum++;
    15         else last=a[i];//只有在不取的时候更新last 
    16     }
    17     if (sum>m) return 0;
    18     return 1;
    19 }
    20 int main()
    21 {
    22     freopen("stone.in","r",stdin);
    23     freopen("stone.out","w",stdout);
    24     cin>>l>>n>>m;
    25     for (int i=1;i<=n;i++)
    26       scanf("%d",&a[i]);
    27     a[n+1]=l;
    28     li=1;ri=l;
    29     while (li<ri){
    30         int mid=(li+ri)>>1;
    31         if (pd(mid)) {
    32             //ans=mid;
    33             li=mid+1;
    34         }
    35         else ri=mid;
    36     }
    37     if (pd(l)) ans=l;//注意特判 
    38     else ans=li-1;
    39     cout<<ans;
    40     return 0;
    41 }
    View Code

      第二题:动态规划。但是我就是这一块不熟,一般动规的题我都不会做。然后这道题理解起来就比较困难。代码贴在这里,解析我觉得这位写的不错:http://blog.csdn.net/XianHaoMing/article/details/51222553  还有滚动数组的思想也需要注意。如果看不懂得话,就看这位的吧:http://www.cnblogs.com/ivorysi/p/5804685.html    我就直接上代码了。。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define maxn 1005
     6 #define inf 1000000000+7
     7 using namespace std;
     8 int n,m,k,cur,last;
     9 string s1,s2;
    10 int s[maxn][205][3],f[maxn][205][3];//s[i][j][k] A
    11 int main()
    12 {
    13     freopen("substring.in","r",stdin);
    14     freopen("substring.out","w",stdout);
    15     cin>>n>>m>>k;
    16     cin>>s1;cin>>s2;
    17     for (int i=0;i<=n;i++) s[i][0][0]=1;//初值
    18     cur=0;last=1;
    19     for (int ki=1;ki<=k;ki++)
    20     {
    21         swap(cur,last);//滚动数组 
    22         for (int j=ki;j<=m;j++)
    23           for (int i=j;i<=n;i++)
    24           {
    25               if (s1[i-1]==s2[j-1])
    26                   {
    27                       f[i][j][cur]=f[i-1][j-1][cur]+s[i-1][j-1][last];
    28                       f[i][j][cur]%=inf;
    29                       f[i-1][j-1][cur]=0;
    30                   }
    31               else f[i][j][cur]=0;
    32               s[i][j][cur]=f[i][j][cur]+s[i-1][j][cur];
    33               s[i][j][cur]%=inf;
    34           }
    35     }
    36     cout<<s[n][m][cur];
    37     return 0;
    38 }
    View Code

      第三题:正解是:LCA+树剖+二分+差分序列。但是我并不想做。所以乱搞了一个30分的代码,但是话说这个代码不应该是60分吗?下次来看哪里有问题。

    看来数据分治很好用啊。。。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define maxn 100005
     6 using namespace std;
     7 int n,m,v[maxn],s[maxn],su[maxn],ma=0,sum[maxn],ans,bb;
     8 int tot,he[maxn],ne[maxn*2],to[maxn*2],w[maxn*2],st,en;
     9 bool vis[maxn];
    10 void add(int a,int b,int c)
    11 {
    12     tot++;ne[tot]=he[a];to[tot]=b;w[tot]=c;he[a]=tot;
    13 }
    14 void dfs(int x,int cur,int suu)
    15 {
    16     if (x==en) {
    17             ans=suu-cur;
    18             return ;
    19     }
    20     for (int i=he[x];i;i=ne[i])
    21     if (!vis[to[i]]){
    22         vis[to[i]]=1;
    23         if (w[i]>cur) dfs(to[i],w[i],suu+w[i]);
    24         else dfs(to[i],cur,suu+w[i]);
    25     }
    26 }
    27 int main()
    28 {
    29     freopen("transport.in","r",stdin);
    30     freopen("transport.out","w",stdout);
    31     cin>>n>>m;
    32     if (m!=1){//处理 链 的情况 
    33         for (int i=1;i<n;i++){
    34             int a,b,c;
    35             scanf("%d%d%d",&a,&b,&c);
    36             v[a]=c;
    37             sum[a]=sum[a-1]+v[a];
    38         }
    39         for (int i=1;i<=m;i++)
    40         {
    41             int a,b;
    42             scanf("%d%d",&a,&b);
    43             s[a]++;s[b]--;
    44             if (sum[b-1]-sum[a-1]>ma) ma=sum[b-1]-sum[a-1];
    45         }
    46         memset(sum,0,sizeof(sum));
    47         for (int i=1;i<=n;i++)
    48           {
    49               sum[i]=sum[i-1]+s[i];
    50               if (v[i]*sum[i]>ans) {
    51                   ans=v[i]*sum[i];
    52                   bb=i;
    53               }
    54           }
    55         cout<<ma-v[bb];
    56     }
    57     else {
    58         for (int i=1;i<n;i++)
    59         {
    60             int a,b,c;
    61             scanf("%d%d%d",&a,&b,&c);
    62             add(a,b,c);
    63             add(b,a,c);
    64         }
    65         scanf("%d%d",&st,&en);
    66         vis[st]=true;
    67         dfs(st,0,0);
    68         cout<<ans;
    69     }
    70     return 0;
    71 }
    View Code

      滚回去看动规了。。。

      
  • 相关阅读:
    HDU5470 Typewriter SAM 动态规划 单调队列
    BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树
    Codeforces 235C Cyclical Quest 字符串 SAM KMP
    HDU4622 Reincarnation 字符串 SAM
    Codeforces 452E Three strings 字符串 SAM
    BZOJ3926 [Zjoi2015]诸神眷顾的幻想乡 字符串 SAM
    2018牛客网暑假ACM多校训练赛(第三场)I Expected Size of Random Convex Hull 计算几何,凸包,其他
    2018牛客网暑假ACM多校训练赛(第三场)G Coloring Tree 计数,bfs
    2018牛客网暑假ACM多校训练赛(第三场)D Encrypted String Matching 多项式 FFT
    UOJ#310 【UNR #2】黎明前的巧克力 FWT 多项式
  • 原文地址:https://www.cnblogs.com/lx0319/p/5997906.html
Copyright © 2011-2022 走看看