彩蛋
跳石头
(stone.cpp/c/pas)
【问题描述】
一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石) 。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石) 。
【 数据规模与约定 】
对于 20%的数据,0 ≤ M ≤ N ≤ 10。
对于 50%的数据,0 ≤ M ≤ N ≤ 100。
对于 100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,000。
思路
你看那个L那么大,如果暴力枚举,循环一遍都不行。很明显要减少石头之间的大量没用距离的运算。
利用二分的思想,(二分答案),加上一点点贪心,就是两个石子尽可能靠近。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N=50000;
int l,n,m,maxn,minn,ans,line[N+5];
int find(int x)
{
int num=0,now=0;
for (int i=1;i<=n+1;i++)
if (line[i]-line[now]>=x) num++,now=i;
return num>n-m;
}
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",&line[i]);
line[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",ans);
return 0;
}
子串
(substring.cpp/c/pas)
【问题描述】
有两个仅包含小写英文字母的字符串 A 和 B。 现在要从字符串 A 中取出 k 个 互不重
叠 的非空子串, 然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一
个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出
的位置不同也认为是不同的方案 。
【数据规模与约定】
对于第 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。
思路
首先,一般来说,字符串的题不是用纯的字符串方法,就是用动态规划。
这道题如果用纯的字符串方法,KMP找匹配然后在求组合数?求后缀?很明显不是。再看看这明显的“动规套路”,就知道这是DP了。可以用三维数组,dp【A第i位】【B第i位】【分成p组】,然后两个动规。我用的是一个四维的数组dp【A第i位】【B第i位】【分成p组】【子串是否存在于B中】,然后三个循环内一起搞就好了。
这里要注意了,上述算法是没有正确性上的问题的,时间复杂度也没有问题。但是由于内存的原因,数组不可以开大了,所以要滚动,滚动第一维。可以用&,也可以%,反正把内存降下去了。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
const int mod=1000000007;
const int N=210;
using namespace std;
int n,m,p,s,f[2][N][N][2];
char A[N*5],B[N];
int main()
{
// freopen("substring.in","r",stdin);
// freopen("substring.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);
scanf("%s%s",A+1,B+1);
for(int i=1;i<=n;i++)
{
f[i%2][1][1][0]=s;
if(A[i]==B[1])f[i%2][1][1][1]=1,s++;
for(int j=2;j<=m;j++)
for(int k=1;k<=p;k++)
{
f[i%2][j][k][0]=(f[(i+1)%2][j][k][0]+f[(i+1)%2][j][k][1])%mod;
if(A[i]==B[j]) f[i%2][j][k][1]=((f[(i+1)%2][j-1][k-1][1]+f[(i+1)%2][j-1][k][1])%mod+f[(i+1)%2][j-1][k-1][0])%mod;
}
for(int j=1;j<=m;j++)
for(int k=1;k<=p;k++)
f[(i+1)%2][j][k][1]=f[(i+1)%2][j][k][0]=0;
}
printf("%d\n",(f[n%2][m][p][0]+f[n%2][m][p][1])%mod);
return 0;
}
运输计划
(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 的物流公司完成阶段性工作所需要的最短时间是多少?
思路
我不会。。。代码抄的
代码
#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);
}