1 . 跳石头(stone.cpp/c/pas)
【问题描述】
一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选
择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终
点的岩石) 。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达
终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳
跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能
移走起点和终点的岩石) 。
【输入格式】
输入文件名为 stone.in。
输入文件第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终
点之间的岩石数,以及组委会至多移走的岩石数。
接下来 N 行,每行一个整数,第 i 行的整数 Di( 0 < Di < L )表示第 i 块岩石与
起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同
一个位置。
【输出格式】
输出文件名为 stone.out。
输出文件只包含一个整数,即最短跳跃距离的最大值。
【 数据规模与约定 】
对于 20%的数据,0 ≤ M ≤ N ≤ 10。
对于 50%的数据,0 ≤ M ≤ N ≤ 100。
对于 100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,000。
【解题报告】
二分答案,水
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50010
int n,m,l;
int maxn,minn,ans;
int w[N];
bool find(int step)
{
int num=0,now=0;
for(int i=1;i<=n+1;++i)
if(w[i]-w[now]>=step)
++num,now=i;
return(num>n-m)?1:0;
}
int main()
{
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
scanf("%d%d%d",&l,&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&w[i]);
w[n+1]=l,maxn=l;
while(minn<=maxn)
{
int mid=(maxn+minn)>>1;
if(find(mid)) ans=mid,minn=mid+1;
else maxn=mid-1;
}
printf("%d\n",ans);
return 0;
}
2 . 子串(substring.cpp/c/pas)
【问题描述】
有两个仅包含小写英文字母的字符串 A 和 B。 现在要从字符串 A 中取出 k 个 互不重
叠 的非空子串, 然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一
个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出
的位置不同也认为是不同的方案 。
【输入格式】
输入文件名为 substring.in。
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问
题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。
第三行包含一个长度为 m 的字符串,表示字符串 B。
【输出格式】
输出文件名为 substring.out。
输出共一行,包含一个整数,表示所求方案数。 由于答案可能很大,所以这里要求输
出答案对 1,000,000,007 取模
【数据规模与约定】
对于第 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。
【解题报告】
DP+滚一下,水
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 1050
#define M 250
#define MOD 1000000007
int n,m,s,sum=0;
char A[N],B[M];
int dp[2][M][M][2];
int main()
{
freopen("substring.in","r",stdin);
freopen("substring.out","w",stdout);
scanf("%d%d%d",&n,&m,&s);
scanf("%s%s",A+1,B+1);
for(int i=1;i<=n;++i)
{
dp[i&1][1][1][0]=sum;
if(A[i]==B[1]) sum++,dp[i&1][1][1][1]=1;
for(int j=2;j<=m;++j)
for(int k=1;k<=s;++k)
{
dp[i&1][j][k][0]=(dp[i-1&1][j][k][0]+dp[i-1&1][j][k][1])%MOD;
if(A[i]==B[j])
dp[i&1][j][k][1]=(dp[i-1&1][j-1][k][1]+(dp[i-1&1][j-1][k-1][0]+dp[i-1&1][j-1][k-1][1])%MOD)%MOD;
}
for(int j=1;j<=m;++j)
for(int k=1;k<=s;++k)
dp[i-1&1][j][k][0]=dp[i-1&1][j][k][1]=0;
}
printf("%d\n",(dp[n&1][m][s][0]+dp[n&1][m][s][1])%MOD);
return 0;
}
3. 运输计划(transport.cpp/c/pas)
【问题描述】
公元 2044 年,人类进入了宇宙纪元。
L 国有 n 个星球,还有 n-1 条 双向 航道,每条航道建立在两个星球之间,这 n-1 条
航道 连通 了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物
流飞船需要从 u i 号星球沿 最快 的宇航路径飞行到 v i 号星球去。 显然, 飞船驶过一条航道
是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 t j ,并且任意两艘飞船之
间 不会 产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小
P 把某一条航道改造成虫洞,飞船驶过虫洞 不消耗 时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,
这 m 个运输计划会 同时 开始,所有飞船 一起 出发。当这 m 个运输计划 都完成 时,小 P 的
物流公司的阶段性工作就完成了。
如果小 P 可以 自由选择 将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段
性工作所需要的最短时间是多少?
【输入格式】
输入文件名为 transport.in。
第一行包括两个正整数 n、 m, 表示 L 国中星球的数量及小 P 公司预接的运输计划的
数量,星球从 1 到 n 编号。
接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 a i , b i 和 t i ,表示第
i 条双向航道修建在 a i 与 b i 两个星球之间,任意飞船驶过它所花费的时间为 t i 。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 u j 和 v j ,表示第 j 个
运输计划是从 u j 号星球飞往 v j 号星球。
【输出格式】
输出文件名为 transport.out。
共 1 行,包含 1 个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
【数据规模与约定】
所有测试数据的范围和特点如下表所示
【解题报告】
LCA+查分乱搞,不水,放弃