NOIP 2015 提高组 day2 解题报告
来源:互联网 发布:ajaxupload.js cdn 编辑:程序博客网 时间:2024/05/18 03:08
T1 跳石头:
题目描述 Description
一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有N块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走M块岩石(不能移走起点和终点的岩石)。
输入描述 Input Description
输入文件名为 stone.in。
输入文件第一行包含三个整数L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。
接下来N行,每行一个整数,第i行的整数Di(0 < Di < L)表示第i块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出描述 Output Description
输出文件名为stone.out。
输出文件只包含一个整数,即最短跳跃距离的最大值。
样例输入 Sample Input
25 5 2
2
11
14
17
21
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
对于20%的数据,0≤M≤N≤10。 对于50%的数据,0≤M≤N≤100。
对于50%的数据,0≤M≤N≤100。
对于100%的数据,0≤M≤N≤50,000,1≤L≤1,000,000,000。
题解:
二分答案裸题,对于此类求最小值最大,很多时候需要二分一个答案,这个时候我们进行二分,然后在check(也就是我的query函数)的时候进行计数,如果计的数大于了需要移走的个数,则说明我的距离大了,导致必须移动更多的石头来满足二分到的答案,因此把距离往小二分,反之把距离往大二分
#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<vector>#include<map>#include<set>#define MAXN 50000+50using namespace std;int L,N,M;int cnt;int loc[MAXN];int maxn;int len[MAXN];int query(int num){ int last=0; int cnt=0; for(register int i=1;i<=N+1;i++){ if(loc[i]-last<num) cnt++; else last=loc[i]; } return cnt;}int main(){ freopen("stone.in","r",stdin); freopen("stone.out","w",stdout); scanf("%d%d%d",&L,&N,&M); for(register int i=1;i<=N;i++){ scanf("%d",&loc[i]); len[i]=loc[i]-loc[i-1]; maxn=max(maxn,len[i]); } loc[N+1]=L; len[N+1]=loc[N+1]-loc[N]; maxn=max(maxn,len[N+1]); int l=0; int r=maxn; while(l<=r){ int mid=(l+r)>>1; int temp=query(mid); if(temp>M) r=mid-1; else l=mid+1; } //int te=lower_bound(len+1,len+N+1,l)-len; printf("%d",l-1); return 0;}
这里面的len数组没有什么卵用…懒得删了,之前的思路不一样
对于printf的l-1可以这样思考:
对于while,如果当前的l已经等于r了,那么如果query(mid)成立,那么l就会++,然而大于mid的都是不成立的,所以这个时候输出l–也就是之前的mid,如果query(mid)不成立,那么r就会- -,并且l这处也是不成立的,所以往左走,因为左边的数据都是满足的(因为每次都是只要满足就往右走)
T2:子串
时间限制: 1 s
空间限制: 128000 KB
题目描述 Description
有两个仅包含小写英文字母的字符串A和B。现在要从字符串A中取出k个互不重叠的非空子串,然后把这k个子串按照其在字符串A中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串B相等?注意:子串取出的位置不同也认为是不同的方案。
输入描述 Input Description
第一行是三个正整数n,m,k,分别表示字符串A的长度,字符串B的长度,以及问题描述中所提到的k,每两个整数之间用一个空格隔开。
第二行包含一个长度为n的字符串,表示字符串A。 第三行包含一个长度为m的字符串,表示字符串B。
输出描述 Output Description
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对1,000,000,007取模的结果。
样例输入 Sample Input
【Input1】
6 3 1
aabaab
aab
【Input2】
6 3 2
aabaab
aab
【Input3】
6 3 3
aabaab
aab
样例输出 Sample Output
【Output1】
2
【Output2】
7
【Output3】
7
数据范围及提示 Data Size & Hint
对于第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题
设两串字符的数组名分别为A和B
我们令
令
我们可以自然地推出s的状态转移
可以这样思考
那么
在匹配
如果
第一种是让目前匹配上的和之前的合并,也是匹配了k次,方案数不变
还有一种是让目前的匹配自成一派,也就是之前匹配了k-1次,然后现在再匹配一次
所以可以得到
如果
那么显然此时的
所以现在我们已经得到了所有的s和f数组的状态转移,显然最后的答案在
显然如果两个数组都开三维的话,是会爆空间的,所以我们需要用滚动来优化空间,就像背包一样~
#include<cstdio>#include<cstring>#include<iostream>#define MAXN 1000+10#define MINN 200+20#define idy 1000000007using namespace std;int N,M,K;char A[MAXN],B[MAXN];int f[MAXN][MINN],s[MAXN][MINN];int main(){ scanf("%d%d%d%s%s",&N,&M,&K,&A,&B); s[0][0]=1; for(register int i=1;i<=N;i++){ for(register int j=M;j>=1;j--){ if(A[i-1]==B[j-1]) for(register int k=min(j,K);k>=1;k--){ f[j][k]=(f[j-1][k]+s[j-1][k-1])%idy; s[j][k]=(s[j][k]+f[j][k])%idy; }else fill(f[j],f[j]+min(j,K)+1,0); } } printf("%d",s[M][K]%idy); return 0;}
T3:运输计划
题目描述 Description
公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
输入描述 Input Description
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1<=ai,bi<=n 且 0<=ti<=1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1<=ui,vi<=n
输出描述 Output Description
输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
样例输入 Sample Input
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
样例输出 Sample Output
11
数据范围及提示 Data Size & Hint
样例解释:
将第 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。
测试数据及约定:
所有数据:
1 <= ai, bi, uj, vj <= n, 0 <= ti <= 1000
这道题显然也是一个二分加LCA加差分裸题,比较水,只需要将所有询问的LCA处理出来,然后每次二分最长路径长度,然后寻找非法路径,然后寻找所有路径的交,再在所有路径的交里寻找一条最长的边,然后对所有非法路径减去这条边,判断一下是否满足二分的值就好了
#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<vector>#include<map>#include<set>#define MAXN 300010using namespace std;int readin(){ 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 Line{ int from,to,val,nxt;}line[MAXN*2];struct queryL{ int from,to,nxt,lca;}question[MAXN*2];int n,m,s[MAXN],f[MAXN],dfn[MAXN],dis[MAXN],fa[MAXN],head_line[MAXN],head_question[MAXN],tail_line,tail_question,tail_dfs;void add_line(int from,int to,int val){ tail_line++; line[tail_line].from=from; line[tail_line].to=to; line[tail_line].val=val; line[tail_line].nxt=head_line[from]; head_line[from]=tail_line;}void add_question(int from,int to){ tail_question++; question[tail_question].from=from; question[tail_question].to=to; question[tail_question].nxt=head_question[from]; head_question[from]=tail_question;}void dfs(int u,int father,int cnt){ fa[u]=father; dis[u]=cnt; for(register int i=head_line[u];i;i=line[i].nxt){ int v=line[i].to; if(v!=father) dfs(v,u,cnt+line[i].val); } dfn[++tail_dfs]=u;}int find(int x){if(x==f[x]) return x;else return f[x]=find(f[x]);}void tarjan(int u){ f[u]=u; for(register int i=head_line[u];i;i=line[i].nxt){ int v=line[i].to; if(v!=fa[u]){ tarjan(v); f[v]=u; } } for(register int i=head_question[u];i;i=question[i].nxt){ int t=question[i].to; if(f[t]) question[i].lca=find(t); }}bool check(int maxn){ int ans=0,total=0,Maxn=0; memset(s,0,sizeof(s)); for(register int i=1;i<=tail_question;i+=2){ question[i].lca=max(question[i].lca,question[i+1].lca); int len=dis[question[i].from]+dis[question[i].to]-2*dis[question[i].lca]; if(len>maxn){ total++; s[question[i].from]++; s[question[i].to]++; s[question[i].lca]-=2; Maxn=max(Maxn,len-maxn); } } for(register int i=1;i<=n;i++) s[fa[dfn[i]]]+=s[dfn[i]]; for(register int i=1;i<=n;i++){ if(s[i]==total) ans=max(ans,dis[i]-dis[fa[i]]); } return ans>=Maxn;}int main(){ freopen("transport.in","r",stdin); freopen("transport.out","w",stdout); n=readin();m=readin(); int from,to,val,l=0,r=0; for(register int i=1;i<=n-1;i++){ from=readin();to=readin();val=readin(); add_line(from,to,val),add_line(to,from,val); r+=val; } for(register int i=1;i<=m;i++){ from=readin();to=readin(); add_question(from,to); add_question(to,from); } dfs(1,0,0); tarjan(1); int ans=0; while(l<=r){ int mid=(l+r)>>1; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d",ans); return 0;}
- NOIP 2015 提高组 day2 解题报告
- [解题报告] NOIP 2014 提高组Day2试题
- NOIP 2015 Day2 解题报告
- noip 2015 day2解题报告
- [REVIEW] NOIP 2015 Day2 解题报告
- NOIP 2015 Day2 解题报告(全面)
- NOIP 2016 Day2 解题报告
- 【noip2014提高组】【Day2】【解题报告】
- 【noip2013】【提高组】【Day2】【解题报告】
- NOIP2013提高组Day2 华容道 解题报告
- 2015 NOIP提高组 复赛解题报告 C++
- Noip 2014 提高组复赛 解题报告
- [2011noip day2]7.27test解题报告
- NOIP2015提高组Day2 第二题 子串 解题报告
- [解题报告] NOIP 2014 提高组Day1试题
- 2016 NOIP提高组复赛解题报告 C++
- 2014 NOIP复赛提高组 C++ 解题报告
- NOIP 2015 提高组 复赛 day2 stone 跳石头
- Java集合框架
- seo教程:网站SEO优化的七大基本要点!
- 设置input 的 checkbox样式
- java.text.ParseException: Unparseable date:
- SAPUI5教程——Content Densities
- NOIP 2015 提高组 day2 解题报告
- 提升HBase写性能
- #1 定义组件
- onEditorAction不执行
- NXP JCOP系列芯片卡特点
- 二叉树基本算法
- 【LeetCode】16. 3Sum Closest
- Mysql技术内幕InnoDB存储引擎读书笔记--《六》锁
- 基于注解的关联关系Hibernate(2)——详解+源码