[REVIEW] NOIP 2015 Day2 解题报告

来源:互联网 发布:珠海联邦制药知乎 编辑:程序博客网 时间:2024/05/21 08:03

T1:跳石头

题目背景

一年一度的“跳石头”比赛又要开始了!
题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终 点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达 终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳 跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能 移走起点和终点的岩石)。
输入输出格式
输入格式:

输入文件名为 stone.in。

输入文件第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终 点之间的岩石数,以及组委会至多移走的岩石数。

接下来 N 行,每行一个整数,第 i 行的整数 Di(0 < Di < L)表示第 i 块岩石与 起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同 一个位置。

输出格式:

输出文件名为 stone.out。 输出文件只包含一个整数,即最短跳跃距离的最大值。

输入输出样例
输入样例#1:

25 5 2
2
11
14
17
21

输出样例#1:

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。


【分析】
一道神题
二分答案+贪心

【代码】

//NOIP 2015 跳石头#include<cstdio>#define fo(i,j,k) for(i=j;i<=k;i++)int L,n,m; int a[50005];inline bool can(int x){    int i,j,res=0,last=0;    fo(i,1,n)    {        if(a[i]-last<x) res++;        else last=a[i];    }    if(res<=m) return 1;    return 0;}int main(){    int i,j;    scanf("%d%d%d",&L,&n,&m);    fo(i,1,n)      scanf("%d",&a[i]);    a[++n]=L;    int l=0,r=L;    while(l<r)    {        int mid=(l+r)/2+1;        if(can(mid)) l=mid;        else r=mid-1;    }    printf("%d\n",l);    return 0;} 

T2:子串

【分析】
重构一遍代码感觉好多了…
dp[i][j][k][0] 表示a串前i位,b串前j位,用k个子串来匹配,且 不选 第i位时的方案数,dp[i][j][k][0] 则是选第i位。
空间放不下,数组滚起来

【代码】

//NOIP 2015 D2T2 子串 #include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=1005,mod=1000000007;int n,m,p;int dp[2][205][205][2];  //是否选择了第i位 char a[mxn],b[mxn];int main(){    int i,j,k;    scanf("%d%d%d",&n,&m,&p);    scanf("%s%s",a+1,b+1);    dp[0][0][0][0]=dp[1][0][0][0]=1;    fo(i,1,n)    {        fo(j,1,m)          fo(k,1,p)          {              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][1]+dp[i&1^1][j-1][k][1])%mod,                dp[i&1][j][k][1]=(dp[i&1][j][k][1]+dp[i&1^1][j-1][k-1][0])%mod;          }        fo(j,1,m)          fo(k,1,p)            dp[i&1^1][j][k][0]=dp[i&1^1][j][k][1]=0;    }    printf("%d\n",(dp[n&1][m][p][0]+dp[n&1][m][p][1])%mod);    return 0;}

T3:运输计划
对于这道题…只能喊救命了
图论压轴题就是把各种图论算法结合…还要考你思路。qwq
思路:二分答案+贪心+倍增求lca+打标记dfs+神奇记录方式

//NOIP 2015 D2T3 运输计划 #include<iostream>#include<vector>#include<cstdio>#include<cstring>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=300005;int n,m,cnt;int dep[mxn],head[mxn],vis[mxn],to[mxn][21],w[mxn][21],father[mxn];struct edge{int to,dis,next;}f[mxn*2];struct query{int l,r,anc,dis;}q[mxn];inline void add(int u,int v,int dis){    f[++cnt].to=v;    f[cnt].dis=dis;    f[cnt].next=head[u];    head[u]=cnt;}inline void dfs(int u,int fa){    for(int i=head[u];i;i=f[i].next)    {        int v=f[i].to;        if(v==fa) continue;        dfs(v,u);        vis[u]+=vis[v];    }}inline bool judge(int mid){    int i,j,k,tot=0,mx=0;M(vis);    fo(i,1,m)      if(q[i].dis>mid)      {            tot++;            vis[q[i].l]++,vis[q[i].r]++;            vis[q[i].anc]-=2;            mx=max(mx,q[i].dis-mid);      }    dfs(1,0);    fo(i,1,n)      if(vis[i]==tot && f[father[i]].dis>=mx) return 1;    return 0;}inline void lca(int x,int y,int id){    int i,j,dis=0;    if(dep[x]<dep[y]) swap(x,y);    for(j=19;j>=0;j--)      if(dep[to[x][j]]>=dep[y])        dis+=w[x][j],x=to[x][j];    if(x==y) {q[id].anc=y,q[id].dis=dis;return;}    for(j=19;j>=0;j--)      if(to[x][j]!=to[y][j])        dis+=w[x][j]+w[y][j],x=to[x][j],y=to[y][j];    q[id].anc=to[x][0];    q[id].dis=dis+w[x][0]+w[y][0];}inline void dfs_build(int u,int fa){    for(int i=head[u];i;i=f[i].next)    {        int v=f[i].to;        if(v==fa) continue;        dep[v]=dep[u]+1;        father[v]=i;        dfs_build(v,u);        to[v][0]=u,w[v][0]=f[i].dis;    }}int main(){    int i,j,u,v,d;    scanf("%d%d",&n,&m);    fo(i,2,n)    {        scanf("%d%d%d",&u,&v,&d);        add(u,v,d);        add(v,u,d);    }    dep[1]=1,dfs_build(1,0);    fo(j,1,19)      fo(i,1,n)        to[i][j]=to[to[i][j-1]][j-1],w[i][j]=w[i][j-1]+w[to[i][j-1]][j-1];    fo(i,1,m)    {        scanf("%d%d",&q[i].l,&q[i].r);        lca(q[i].l,q[i].r,i);    }    int l=0,r=1e9;    while(l<r)    {        int mid=(l+r)/2;        if(judge(mid)) r=mid;        else l=mid+1;    }    printf("%d\n",l);    return 0;}
1 0