【NOIP2015】提高day2解题报告

时间:2024-01-02 09:47:26

题目:

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%的数据,0≤M≤N≤100≤M≤N≤10
对于50%的数据,0≤M≤N≤1000≤M≤N≤100
对于100%的数据,0≤M≤N≤500000≤M≤N≤500001≤L≤10000000001≤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 个星球,还有 n−1n−1 条双向航道,每条航道建立在两个星球之间,这 n−1n−1 条 航道连通了 L 国的所有星球。

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

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

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

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

格式

输入格式

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

接下来 n−1n−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,就取左区间。注意二分的模板和 判重 。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50005
using namespace std;
int n,m,l,li,ri,ans;
int a[maxn];
bool pd(int x)
{
int last=,sum=;
for (int i=;i<=n+;i++)// n+1
{
if (a[i]-last<x) sum++;
else last=a[i];//只有在不取的时候更新last
}
if (sum>m) return ;
return ;
}
int main()
{
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
cin>>l>>n>>m;
for (int i=;i<=n;i++)
scanf("%d",&a[i]);
a[n+]=l;
li=;ri=l;
while (li<ri){
int mid=(li+ri)>>;
if (pd(mid)) {
//ans=mid;
li=mid+;
}
else ri=mid;
}
if (pd(l)) ans=l;//注意特判
else ans=li-;
cout<<ans;
return ;
}

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

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1005
#define inf 1000000000+7
using namespace std;
int n,m,k,cur,last;
string s1,s2;
int s[maxn][][],f[maxn][][];//s[i][j][k] A
int main()
{
freopen("substring.in","r",stdin);
freopen("substring.out","w",stdout);
cin>>n>>m>>k;
cin>>s1;cin>>s2;
for (int i=;i<=n;i++) s[i][][]=;//初值
cur=;last=;
for (int ki=;ki<=k;ki++)
{
swap(cur,last);//滚动数组
for (int j=ki;j<=m;j++)
for (int i=j;i<=n;i++)
{
if (s1[i-]==s2[j-])
{
f[i][j][cur]=f[i-][j-][cur]+s[i-][j-][last];
f[i][j][cur]%=inf;
f[i-][j-][cur]=;
}
else f[i][j][cur]=;
s[i][j][cur]=f[i][j][cur]+s[i-][j][cur];
s[i][j][cur]%=inf;
}
}
cout<<s[n][m][cur];
return ;
}

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

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

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100005
using namespace std;
int n,m,v[maxn],s[maxn],su[maxn],ma=,sum[maxn],ans,bb;
int tot,he[maxn],ne[maxn*],to[maxn*],w[maxn*],st,en;
bool vis[maxn];
void add(int a,int b,int c)
{
tot++;ne[tot]=he[a];to[tot]=b;w[tot]=c;he[a]=tot;
}
void dfs(int x,int cur,int suu)
{
if (x==en) {
ans=suu-cur;
return ;
}
for (int i=he[x];i;i=ne[i])
if (!vis[to[i]]){
vis[to[i]]=;
if (w[i]>cur) dfs(to[i],w[i],suu+w[i]);
else dfs(to[i],cur,suu+w[i]);
}
}
int main()
{
freopen("transport.in","r",stdin);
freopen("transport.out","w",stdout);
cin>>n>>m;
if (m!=){//处理 链 的情况
for (int i=;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
v[a]=c;
sum[a]=sum[a-]+v[a];
}
for (int i=;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
s[a]++;s[b]--;
if (sum[b-]-sum[a-]>ma) ma=sum[b-]-sum[a-];
}
memset(sum,,sizeof(sum));
for (int i=;i<=n;i++)
{
sum[i]=sum[i-]+s[i];
if (v[i]*sum[i]>ans) {
ans=v[i]*sum[i];
bb=i;
}
}
cout<<ma-v[bb];
}
else {
for (int i=;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
scanf("%d%d",&st,&en);
vis[st]=true;
dfs(st,,);
cout<<ans;
}
return ;
}

  滚回去看动规了。。。