1890:【15NOIP提高组】跳石头
时间限制: 1000 ms 内存限制: 131072 KB
提交数: 1037 通过数: 561
【题目描述】
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳 跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走M块岩石(不能 移走起点和终点的岩石)。
【输入】
一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终 点之间的岩石数,以及组委会至多移走的岩石数。
接下来N行,每行一个整数,第i行的整数 Di(0 < Di < L)表示第i块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
【输出】
只包含一个整数,即最短跳跃距离的最大值。
【输入样例】
25 5 2
2
11
14
17
21
【输出样例】
4
【提示】
输入输出样例1说明:将与起点距离为2和14的两个岩石移走后,最短的跳跃距离为4(从与起点距离17的岩石跳到距离21的岩石,或者从距离21的岩石跳到终点)。
其它输入输出样例下载
数据范围:
对于20%的数据,0 ≤ M ≤ N ≤ 10。
对于50%的数据,0 ≤ M ≤ N ≤ 100。
对于100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,000。
#include<iostream>
#include<cstdio>
using namespace std;
int leng,n,m,a[50002];
bool check(int x){
int last=0;
int sum=0;
for(int i=1;i<=n;i++){
if(a[i]-last>=x){
last=a[i];
}else{
sum++;
}
}
if(leng-last<x){
sum++;
}
return sum<=m;
}
int main(){
cin>>leng>>n>>m;
int l=1,r=leng;
for(int i=1;i<=n;i++){
cin>>a[i];
}
while(r>l){
int mid=(l+r+1)>>1;
if(check(mid)){
l=mid;
}else{
r=mid-1;
}
}
cout<<l;
return 0;
}
1891:【15NOIP提高组】子串
时间限制: 1000 ms 内存限制: 131072 KB
提交数: 244 通过数: 136
【题目描述】
有两个仅包含小写英文字母的字符串AA和BB。现在要从字符串AA中取出kk个互不重叠的非空子串,然后把这kk个子串按照其在字符串AA中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串BB相等?注意:子串取出的位置不同也认为是不同的方案。
【输入】
第一行是三个正整数 n,m,kn,m,k,分别表示字符串AA的长度,字符串BB的长度,以及问题描述中所提到的kk,每两个整数之间用一个空格隔开。 第二行包含一个长度为nn的字符串,表示字符串 AA。第三行包含一个长度为mm的字符串,表示字符串BB。
【输出】
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,0071,000,000,007 取模的结果。
【输入样例】
6 3 1
aabaab
aab
【输出样例】
2
【提示】
样例2:
输入:
6 3 2
aabaab
aab
输出:
7
样例3:
输入:
6 3 3
aabaab
aab
输出:
7
输入输出样例说明:
所有合法方案如下:(加下划线的部分表示取出的子串)
其它输入输出样例下载
数据规模与约定:
对于第1组数据:1≤n≤500,1≤m≤50,k=11≤n≤500,1≤m≤50,k=1;
对于第2组至第3组数据:1≤n≤500,1≤m≤50,k=21≤n≤500,1≤m≤50,k=2;
对于第4组至第5组数据:1≤n≤500,1≤m≤50,k=m1≤n≤500,1≤m≤50,k=m;
对于第1组至第7组数据:1≤n≤500,1≤m≤50,1≤k≤m1≤n≤500,1≤m≤50,1≤k≤m;
对于第1组至第9组数据:1≤n≤1000,1≤m≤100,1≤k≤m1≤n≤1000,1≤m≤100,1≤k≤m;
对于所有10组数据:1≤n≤1000,1≤m≤200,1≤k≤m1≤n≤1000,1≤m≤200,1≤k≤m。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define P 1000000007
using namespace std;
int n,m,K,t=1;
int f[2][205][205][2];
char A[1005],B[205];
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
int main(){
scanf("%d%d%d",&n,&m,&K);
scanf("%s%s",A+1,B+1);
f[0][0][0][0]=1;
for(int i=1;i<=n;++i){
f[t][0][0][0]=1;
for(int j=1;j<=m;++j){
for(int k=1;k<=m;++k){
f[t][j][k][0]=add(f[t^1][j][k][0],f[t^1][j][k][1]);
f[t][j][k][1]=(A[i]==B[j])?add(add(f[t^1][j-1][k][1],f[t^1][j-1][k-1][1]),f[t^1][j-1][k-1][0]):0;
}
}
t^=1;
}
printf("%d\n",add(f[t^1][m][K][0],f[t^1][m][K][1]));
return 0;
}
1892:【15NOIP提高组】运输计划
时间限制: 1000 ms 内存限制: 262144 KB
提交数: 614 通过数: 100
【题目描述】
公元2044年,人类进入了宇宙纪元。
L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球。
小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去。显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新,L国国王同意小P的物流公司参与L国的航道建设,即允许小P把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小P的物流公司就预接了m个运输计划。在虫洞建设完成后, 这m个运输计划会同时开始,所有飞船一起出发。当这m个运输计划都完成时,小P的物流公司的阶段性工作就完成了。
如果小P可以自由选择将哪一条航道改造成虫洞,试求出小P的物流公司完成阶段性工作所需要的最短时间是多少?
【输入】
第一行包括两个正整数 n、m,表示L国中星球的数量及小P公司预接的运输计划的数量,星球从1到n编号。
接下来n-1行描述航道的建设情况,其中第i行包含三个整数ai,bi和ti,表示第i条双向航道修建在ai与bi两个星球之间,任意飞船驶过它所花费的时间为ti。接下来m行描述运输计划的情况,其中第j行包含两个正整数uj和vj,表示第j个运输计划是从 uj号星球飞往vj号星球。
【输出】
共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。
【输入样例】
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
【输出样例】
11
【提示】
输入输出样例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。
其它输入输出样例下载
所有测试数据的范围和特点如下表所示:
对于100%的数据,100≤n≤300000,1≤m≤300000100≤n≤300000,1≤m≤300000。
请注意常数因子带来的程序效率上的影响。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=300005;
int N,M,np=0,last[MAXN],dis[MAXN],dep[MAXN],size[MAXN],fa[MAXN],val[MAXN];
int dfs_clock=0,dfs_pos[MAXN],big_son[MAXN],top_node[MAXN];
int tot=0,root=0,lc[MAXN*2],rc[MAXN*2],MAX[MAXN*2],lazy[MAXN*2];
struct edge{int to,w,pre;}E[MAXN*2];
struct data{int l,r;};
data a[MAXN],k[MAXN];
bool cmp(data a,data b) {return a.l<b.l;}
char c;
void scan(int &x)
{
for(c=getchar();c<'0'||c>'9';c=getchar());
for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}
void addedge(int u,int v,int w)
{
E[++np]=(edge){v,w,last[u]};
last[u]=np;
}
void dfs1(int i)
{
for(int p=last[i];p;p=E[p].pre)
{
int j=E[p].to;
if(j==fa[i]) continue;
fa[j]=i;
dep[j]=dep[i]+1;
dis[j]=dis[i]+E[p].w;
size[j]=1;
val[j]=E[p].w;
dfs1(j);
size[i]+=size[j];
if(size[j]>size[big_son[i]]) big_son[i]=j;
}
}
void dfs2(int i,int top)
{
dfs_pos[i]=++dfs_clock;
top_node[i]=top;
if(!big_son[i]) return;
dfs2(big_son[i],top);
for(int p=last[i];p;p=E[p].pre)
{
int j=E[p].to;
if(j==fa[i]||j==big_son[i]) continue;
dfs2(j,j);
}
}
int LCA(int u,int v)
{
while(top_node[u]!=top_node[v])
{
if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
u=fa[top_node[u]];
}
if(dep[u]>dep[v]) swap(u,v);
return u;
}
void build(int &now,int L,int R)
{
if(!now) now=++tot;
if(L==R) return;
int mid=(L+R)/2;
build(lc[now],L,mid);
build(rc[now],mid+1,R);
}
void pushup(int now) {MAX[now]=max(MAX[lc[now]],MAX[rc[now]]);}
void pushdown(int now)
{
if(!lazy[now]) return;
int l=lc[now],r=rc[now],w=lazy[now];
MAX[l]=max(MAX[l],w); lazy[l]=max(lazy[l],w);
MAX[r]=max(MAX[r],w); lazy[r]=max(lazy[r],w);
lazy[now]=0;
}
void update(int now,int L,int R,int i,int j,int w)
{
if(j<i) return;
if((i<=L)&&(R<=j))
{
MAX[now]=max(MAX[now],w);
lazy[now]=max(lazy[now],w);
return;
}
pushdown(now);
int mid=(L+R)/2;
if(i<=mid) update(lc[now],L,mid,i,j,w);
if(mid<j) update(rc[now],mid+1,R,i,j,w);
pushup(now);
}
int query(int now,int L,int R,int pos)
{
if(L==pos&&R==pos) return MAX[now];
pushdown(now);
int mid=(L+R)/2;
if(pos<=mid) return query(lc[now],L,mid,pos);
return query(rc[now],mid+1,R,pos);
}
void tree_up(int id,int w)
{
int u=a[id].l,v=a[id].r,cnt=0;
while(top_node[u]!=top_node[v])
{
if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
k[++cnt]=(data){dfs_pos[top_node[u]],dfs_pos[u]};
u=fa[top_node[u]];
}
if(dep[u]>dep[v]) swap(u,v);
k[++cnt]=(data){dfs_pos[u]+1,dfs_pos[v]}; //注意同一条链上的节点,深度小的不能更新
sort(k+1,k+1+cnt,cmp);
if(k[1].l>1) update(root,1,N,1,k[1].l-1,w); //特判1,N
if(k[cnt].r<N) update(root,1,N,k[cnt].r+1,N,w);