NOIP 2015 DAY2

跳石头

题目背景

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

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 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。

#include<iostream>
#include<cstdio>

using namespace std;
int n,m,L;
int a[50005],ans;

int check(int x)
{
    int last=0,cnt=0;
    for(int i=0;i<=n;i++)
    {
        if(a[i]-last<x){cnt+=1;continue;}
        last=a[i];
    }
    if(cnt>m) return 0;
    return 1;
}

int main()
{
    scanf("%d%d%d",&L,&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    a[n]=L;
    int r=L,l=1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(check(mid)){ans=mid;l=mid+1;}
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

子串

题目背景

题目描述

有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。

输入输出格式

输入格式:

输入文件名为 substring.in。

第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问

题描述中所提到的 k,每两个整数之间用一个空格隔开。 第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。

输出格式:

输出文件名为 substring.out。 输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求[b]输出答案对 1,000,000,007 取模的结果。[/b]

输入输出样例

输入样例#1:

6 3 1
aabaab
aab

输出样例#1:

2

输入样例#2:

6 3 2
aabaab
aab

输出样例#2:

7

输入样例#3:

6 3 3
aabaab
aab

输出样例#3:

7

说明

对于第 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。

/*
状态f[i][j][k] 表示A串匹配到i B串匹配到j 用了k个子串
转移的话 f[i][j][k]=f[i-1][j-1][k]+f[i-1][j-1][k-1]分别表示i是不是建立了一个新的子串
当然这是我们会发现 这样的状态是默认了i用了 显然i可以不用 也就是说这样就遗漏了许多状态
我们重新定义一下他 加一维01表示i用了没用 f[i][j][k][0或1]
这样转移就要分开考虑01
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]因为i没有用 所以不会有新串k不变 B串也不会更新匹配j不变
f[i][j][k][1]=f[i-1][j-1][k-1][0]+f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1]
*/
#include<iostream>
#include<cstring>
#include<cstdio>

#define mod 1000000007
#define maxn 210

using namespace std;
int n,m,p,s,f[2][maxn][maxn][2];
char A[maxn*5],B[maxn];

int main()
{
    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]=0,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;
} 

运输计划

题目背景

公元 2044 年,人类进入了宇宙纪元。

题目描述

L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。

小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?

输入输出格式

输入格式:

输入文件名为 transport.in。

第一行包括两个正整数 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的物流公司完成阶段性工作所需要的最短时间。

输入输出样例

输入样例#1:

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

输出样例#1:

11

说明

所有测试数据的范围和特点如下表所示

请注意常数因子带来的程序效率上的影响。

#include<iostream>
#include<cstdio>
#include<cstring>

#define N 100001

using namespace std;
int head[N<<1],t[N],f[N][25],g[N][25],sum[N],deep[N];
int n,m,x,y,z,ans,tot,cnt,tmp;
struct edge
{
    int u,to,next,dis;
}e[N<<1];

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}

inline void add(int u,int to,int dis)
{
    e[++cnt].to=to;e[cnt].next=head[u];e[cnt].dis=dis;head[u]=cnt;
}

inline void get_fa()
{
    for(int j=1;j<=22;j++)
      for(int i=1;i<=n;i++)
        {
            f[i][j]=f[f[i][j-1]][j-1];
            g[i][j]=max(g[i][j-1],g[f[i][j-1]][j-1]);
        }
}

void dfs(int now,int fa,int c,int wa)
{
    f[now][0]=fa;deep[now]=c;g[now][0]=wa;sum[now]+=wa;
    for(int i=head[now];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa)
        {
            sum[v]+=sum[now];
            dfs(v,now,c+1,e[i].dis);
        }
    }
}

int lca(int a,int b)
{
    if(deep[a]<deep[b]) swap(a,b);
    int t=deep[a]-deep[b];
    for(int i=0;i<=22;i++)
    {
        if(t&(1<<i))
        {
            tmp=max(g[a][i],tmp);
            a=f[a][i];
        }
    }
    if(a==b) return a;
    for(int i=21;i>=0;i--)
    {
        if(f[a][i]!=f[b][i])
        {
            tmp=max(tmp,g[a][i]);
            tmp=max(tmp,g[b][i]);
            a=f[a][i];b=f[b][i];
        }
    }
    tmp=max(tmp,max(g[a][0],g[b][0]));
    return f[a][0];
}

int main()
{
    n=read();m=read();
    if(m==1)
    {
        for(int i=1;i<n;++i)
        {
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
        }
        dfs(1,1,0,0);get_fa();
        x=read();y=read();int L=lca(x,y);
        ans=sum[x]+sum[y]-2*sum[L]-tmp;
        printf("%d\n",ans);
    }
    return 0;
}

20暴力

/*
最后一个点T了 qian lv ji qiong 了
没学过树剖 听chx听xzc说的神奇的方法  Orz
首先求出每个计划的路径长度 这里写的倍增
然后二分答案
对于每个ans 统计>他的路径条数 tot 并维护与ans的最大差值 dec
并且对于每条不合法的路径维护每个点的经过次数
然后枚举点 如果经过次数==tot说明每一条不合法的都经过他
然后尝试把它建成虫洞 如果他对应边的权值>=dec 那么我们删掉它ans就合法了
关键是统计每个点在非法路径中的经过次数 :
维护sum数组 对于每个非法的路径起点a b LCA(a,b)==s sum[a]++ sum[b]++ sum[s]-=2
这样网上更新的话 经过的点的sum值都变成1 祖先s的变成0
这样就实现了sum数组的维护
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define maxn 300100
using namespace std;
int n,m,num,head[maxn],ans,inf;
int fa[maxn][30],dep[maxn],dis[maxn],sum[maxn],edge[maxn];
struct node
{
    int u,v,t,pre;
}e[maxn*2];
struct Ans
{
    int ai,bi,anc,di;
}lca[maxn];
int init()
{
    int x=0;char s=getchar();
    while(s<‘0‘||s>‘9‘)s=getchar();
    while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();}
    return x;
}
void Add(int from,int to,int dis)
{
    num++;
    e[num].u=from;
    e[num].v=to;
    e[num].t=dis;
    e[num].pre=head[from];
    head[from]=num;
}
void Dfs(int now,int from,int c,int Dis)
{
    fa[now][0]=from;
    dep[now]=c;dis[now]=Dis;
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
        {
          edge[e[i].v]=i;
          Dfs(e[i].v,now,c+1,Dis+e[i].t);
        }
}
void Get_fa()
{
    for(int j=1;j<=16;j++)
      for(int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
}
int Get_same(int a,int t)
{
    for(int i=0;i<16;i++)
     if(t&(1<<i)) a=fa[a][i];
    return a;
}
int LCA(int a,int b)
{
    if(dep[a]<dep[b])swap(a,b);
    a=Get_same(a,dep[a]-dep[b]);
    if(a==b)return a;
    for(int i=16;i>=0;i--)
      if(fa[a][i]!=fa[b][i])
        {
          a=fa[a][i];
          b=fa[b][i];
        }
    return fa[a][0];
}
void Init()
{
    n=init();m=init();
    int u,v,t;
    for(int i=1;i<=n-1;i++)
      {
          u=init();v=init();t=init();
          Add(u,v,t);Add(v,u,t);
      }
    Dfs(1,1,0,0);
    Get_fa();
    for(int i=1;i<=m;i++)
      {
          lca[i].ai=init();lca[i].bi=init();
          lca[i].anc=LCA(lca[i].ai,lca[i].bi);
          lca[i].di=dis[lca[i].ai]+dis[lca[i].bi]-2*dis[lca[i].anc];
          inf=max(inf,lca[i].di);
      }
}
void Up_sum(int now,int from)
{
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
        {
          Up_sum(e[i].v,now);
          sum[now]+=sum[e[i].v];
        }
}
int Judge(int x)
{
    memset(sum,0,sizeof(sum));
    int tot=0,dec=0;
    for(int i=1;i<=m;i++)
      if(lca[i].di>x)//非法路径
        {
          tot++;
          dec=max(dec,lca[i].di-x);//最长非法路径与ans差值
          sum[lca[i].ai]++;
          sum[lca[i].bi]++;
          sum[lca[i].anc]-=2;
        }
    Up_sum(1,1);//更新sum数组
    for(int i=1;i<=n;i++)
      if(tot==sum[i]&&e[edge[i]].t>=dec)//删掉edge[i]这条边之后答案合法了
        return 1;
    return 0;
}
void Solve()//二分答案
{
    int l=0,r=inf;
    while(l<=r)
      {
          int mid=(l+r)/2;
          int tmp=Judge(mid);
          if(tmp==1)
            {
                r=mid-1;
                ans=mid;
          }
        else l=mid+1;
      }
}
void Printf()
{
    printf("%d\n",ans);
}
int main()
{
    Init();
    Solve();
    Printf();
    return 0;
}

/*
实在羞于打上自己的分数:10+10+20=40;
试问一下,这要是放在考场上呢?!读错题,没考虑全面是理由吗!!!
T1 10分!!以前还做过。T2连hash暴力都写挂...我不想多数什么,dp方程没有耐心推,暴力没耐心调。连个小数据都舍不得造!
很基础的东西都忘了怎么写!
不管怎样,这就noip了,希望自己有数,提高效率!!!耐心 。
*/

conclusion

时间: 2024-10-17 12:57:40

NOIP 2015 DAY2的相关文章

NOIp 2013 Day2 解题报告

NOIp 2013 Day2 解题报告 1.   积木大赛 每次只要选取连续最大的一段区间即可. 继续归纳可得,答案为∑i=1nmax{0,hi-hi-1} 复杂度O(N) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable/

我的 NOIP 2015

2015,OI 生涯最后一个完整的赛季 从今年的Noip就已经开始了.说起来自己也是从七年级升八年级的暑假就开始接触OI了,不过和许多人一样,一直都是”混“,不知道自己到底在干什么,也没用什么功,每次noip都是考前一两个月才想起来要学OI,然后胡乱刷上几道题,就这么草草参加联赛,每次都是很虚地参加比赛,这次也是,其实到头来都是自己水平太差了,感觉好像考前也挺重视的,实际上也没什么行动,肚子里没点题目,手上怎么能熟练,上了考场紧张也是自然的,所以今年也就因为这紧张的心情Day1 也没发挥好,当然

noip 2015 day1

T1 神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则

noip 2015

情断斗地主,无力跳石头. ——题记(摘自llgyc) day0:第一次做动车,去年居然在初赛就挂,一直幻想着能弥补去年的遗憾..10点才到,直接洗洗睡.. day1:T1直接模拟..T2找最小环dfs即可,没注意图不联通卡了一小会.. 然后看到T3斗地主就傻了..T3看起来代码量有点大,想了好一会儿才下手..状态压缩+bfs..然后就打了不造多久才打完.. 总感觉会T,想加优先级优化下但样例还没过,代码量有点大就不写了.. 然而样例二一直过不了,出来后才发现我一直认为1.2比3小...(我怎么那

NOIP 2015 游记

本来和zly和wxh约好了 高三一起再来玩一次复赛,结果最终只有我一个人来了说...貌似是年段主任不让去...总算见识了比我们学校的YSD更爱管闲事的年段主任. 今年比赛竟然在衢州二中,学校不大,但感觉历史还是挺悠久的.报名费竟然涨了80,CCF又来骗钱了.住的酒店感觉没有以前高级,Wifi弱得只有1格信号,只能看看小说消遣了.晚上随便点了场CF的比赛打了一下,太久没碰这玩意只会Div2的水题了.然后C题一个小错误看了半个小时才看出来,E题写出来了来不及调试,只好滚去睡觉,有一种day1要滚粗的

NOIP 2012 Day2

tags: 扩展欧几里得 二分答案 查分 倍增 二分答案 贪心 NOIP categories: 信息学竞赛 总结 同余方程 借教室 疫情控制 同余方程 Solution 首先同余式可以转化为等式. \[ax\equiv 1\mod b\Leftrightarrow ax+by=1\] 根据扩展欧几里得定理, 对于式 \[ax+by=k(a,b),k\in \mathbf{R}\]一定存在整数解.然而题面说一定存在解, 也就是说\((a,b)=1\), 然后就可以利用扩展欧几里得递归求得一组解.

NOIP 2015普及组复赛Day1 T1 == Codevs4510 神奇的幻方

时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description: 幻方是一种很神奇的N∗N矩阵:它由数字 1,2,3, … … ,N∗N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将 1写在第一行的中间.之后,按如下方式从小到大依次填写每个数(K= 2,3, … ,N∗N ): 1.若 (K−1)在第一行但不在最后一列,则将 填在最后一行,(K−1)所在列的右一列: 2.若 (K

NOIP 2015 子串

借鉴大神思路... 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<queue> 6 #include<stack> 7 #include<cmath> 8 #include<algorithm> 9 #include<malloc.h> 10 using names

NOIP 2015:信息传递

题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象(注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象).当有人从别人口中得知自己的生日时,游戏结束.请问该游戏一共可以进行几轮? 输入输出格式 输入格式: 输入共2行. 第1行包含1个正整数n表示