noip2015 总结

DAY1

T1根据题目描述模拟就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 100
using namespace std;
int ai[maxm][maxm]={0};
int main(){
    freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);

    int n,i,j,x,y,up;
    scanf("%d",&n);
    up=n*n;ai[1][n/2+1]=1;
    x=1;y=n/2+1;
    for (i=2;i<=up;++i){
        if (x==1&&y!=n){
            x=n;++y;ai[x][y]=i;continue;
        }if (y==n&&x!=1){
            --x;y=1;ai[x][y]=i;continue;
        }if (x==1&&y==n){
            ++x;ai[x][y]=i;continue;
        }if (!ai[x-1][y+1]){
            --x;++y;ai[x][y]=i;continue;
        }++x;ai[x][y]=i;
    }for (i=1;i<=n;++i){
      for (j=1;j<=n;++j) printf("%d ",ai[i][j]);
      printf("\n");
    }

    fclose(stdin);
    fclose(stdout);
}

T2tarjan or dfs or spfa

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 400005
using namespace std;
int point[maxm]={0},next[maxm]={0},en[maxm]={0},scnt=0,zh[maxm]={0},pre[maxm]={0},low[maxm]={0},ti=0,
    siz[maxm]={0},sccno[maxm]={0},tot=0;
void add(int u,int v){next[++tot]=point[u];point[u]=tot;en[tot]=v;}
void tarj(int u){
    int i,j,v;zh[++zh[0]]=u;
    pre[u]=low[u]=++ti;
    for (i=point[u];i;i=next[i]){
        if (!pre[v=en[i]]){
            tarj(v);low[u]=min(low[u],low[v]);
        }else{
            if (!sccno[v]) low[u]=min(low[u],pre[v]);
        }
    }if (pre[u]==low[u]){
        ++scnt;
        while(zh[0]>0){
            v=zh[zh[0]--];
            sccno[v]=scnt;++siz[scnt];
            if (v==u) break;
        }
    }
}
int main(){
    freopen("message.in","r",stdin);
    freopen("message.out","w",stdout);

    int n,i,j,v,ans;scanf("%d",&n);
    for (i=1;i<=n;++i){scanf("%d",&v);add(i,v);}
    for (i=1;i<=n;++i)
        if (!pre[i]) tarj(i);
    ans=n;
    for (i=1;i<=scnt;++i)
      if (siz[i]>1) ans=min(ans,siz[i]);
    printf("%d\n",ans);

    fclose(stdin);
    fclose(stdout);
}

T3 landlords

题目大意:给定一副牌,求最少出牌次数。

思路:dfs+一些优化

DAY2

T1二分+贪心判断。(考场上还是耗了一些时间,考场上和平时的思路还是有差距)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 50005
using namespace std;
int di[maxm]={0},n,m,l;
bool judge(int x){
    int i,j,la=0,cnt=0;
    for (i=1;i<=n+1;++i){
        if (di[i]-di[la]<x) ++cnt;
        else la=i;
    }return (cnt<=m);
}
int main(){
    freopen("stone.in","r",stdin);
    freopen("stone.out","w",stdout);

    int i,j,ll,rr,mid,ans;
    scanf("%d%d%d",&l,&n,&m);
    for (i=1;i<=n;++i) scanf("%d",&di[i]);
    di[n+1]=l;ll=0;rr=l;
    while(ll<=rr){
        mid=(ll+rr)/2;
        if (judge(mid)){ans=mid;ll=mid+1;}
        else rr=mid-1;
    }printf("%d\n",ans);

    fclose(stdin);
    fclose(stdout);
}

T2dp+前缀和优化。(考场上只写了一个裸的dp,想到可以前缀和优化了,但是下标的问题没有调出来)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 1005
#define maxx 205
#define p 1000000007
using namespace std;
int fi[2][maxm][maxx]={0},pre[maxm][maxm]={0},gi[2][maxm][maxx]={0};
char s1[maxm],s2[maxm];
char in(){
    char ch=getchar();
    while(ch<‘a‘||ch>‘z‘) ch=getchar();
    return ch;
}
int main(){
    int i,j,t,n,m,k,cur=0,a;
    scanf("%d%d%d",&n,&m,&k);
    for (i=1;i<=n;++i) s1[i]=in();
    for (i=1;i<=m;++i) s2[i]=in();
    for (i=1;i<=n;++i)
      for (j=1;j<=m;++j)
          if (s1[i]==s2[j])
              pre[i][j]=max(pre[i][j],pre[i-1][j-1]+1);
    for(cur=i=0;i<=n;++i) fi[cur][i][0]=1;
    for (i=0;i<=n;++i)
      for (j=0;j<=m;++j) gi[cur][i][j]=(gi[cur][i-1][j-1]+fi[cur][i][j])%p;
    for (t=1;t<=k;++t){
        cur^=1;memset(fi[cur],0,sizeof(fi[cur]));
        for (i=1;i<=n;++i)
          for (j=1;j<=m;++j){
              if (j>i) break;
              fi[cur][i][j]=((gi[cur^1][i-1][j-1]-gi[cur^1][i-pre[i][j]-1][j-pre[i][j]-1]+
                  fi[cur][i-1][j])%p+p)%p;
          }
        for (i=0;i<=n;++i)
          for (j=0;j<=m;++j)
              gi[cur][i][j]=(gi[cur][i-1][j-1]+fi[cur][i][j])%p;
    }printf("%d\n",fi[cur][n][m]);
}

T3 transport

题目大意:给定一棵树和一些链,可以改动一条边为0,求所有链上边权和的最大值最小是多少。

思路:考场上只写了nm的暴力,60分。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 600005
using namespace std;
int point[maxm]={0},next[maxm]={0},en[maxm]={0},va[maxm]={0},tot,v1[maxm]={0},v2[maxm]={0},
    dep[maxm]={0},ed[maxm]={0},fa[maxm]={0},du[maxm]={0};
bool vi[maxm]={false};
void add(int u,int v,int vv){
    next[++tot]=point[u];point[u]=tot;en[tot]=v;va[tot]=vv;
    next[++tot]=point[v];point[v]=tot;en[tot]=u;va[tot]=vv;
}
void dfs(int u,int ff){
    int i,j,v;dep[u]=dep[ff]+1;fa[u]=ff;
    for (i=point[u];i;i=next[i])
        if ((v=en[i])!=ff){dfs(v,u);ed[v]=i;}
}
int work(int u,int v){
    int i,j,sum=0;if (dep[u]<dep[v]) swap(u,v);
    while(dep[u]>dep[v]){
        vi[ed[u]]=vi[ed[u]^1]=true;
        sum+=va[ed[u]];u=fa[u];
    }while(u!=v){
        vi[ed[u]]=vi[ed[u]^1]=vi[ed[v]]=vi[ed[v]^1]=true;
        sum+=va[ed[u]]+va[ed[v]];
        u=fa[u];v=fa[v];
    }return sum;
}
int main(){
    freopen("transport.in","r",stdin);
    freopen("transport.out","w",stdout);

    int n,m,i,j,u,v,vv,ans,ci=0;tot=1;
    scanf("%d%d",&n,&m);ans=2100000000;
    for (i=1;i<n;++i){
        scanf("%d%d%d",&u,&v,&vv);add(u,v,vv);
    }dfs(1,0);
    for (i=1;i<=m;++i){
        scanf("%d%d",&u,&v);
        for (j=2;j<=tot;++j) vi[j]=false;
        vv=work(u,v);
        for (j=2;j<=tot;++j){
            if (!vi[j]) v2[j]=max(v2[j],vv);
            else v1[j]=max(v1[j],vv);
        }
    }for (i=2;i<=tot;++i)
        ans=min(ans,max(v1[i]-va[i],v2[i]));
    printf("%d\n",ans);

    fclose(stdin);
    fclose(stdout);
}

其实看到最大值最小还是首先想二分,但是不会判断。后来听了ta爷的讲解,才明白。其实二分完了之后,我们就是判断一下能否把所有超过二分答案的链的某一条公共边改为0之后使得这些链都不超过答案,可以首先记录有多少这样的链,然后利用差分的思想在树上记录一下,然后前缀和的话就可以考虑到每一条边能否被所有边覆盖了,对于能覆盖的边就可以取一个max,最后判断能否满足条件。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxm 300005
#define maxe 600005
#define up 20
using namespace std;
struct use{
    int u,v,lc,di;
}ask[maxm]={0};
int point[maxm]={0},en[maxe],va[maxe],next[maxe]={0},tot=0,fa[maxm][up]={0},dep[maxm]={0},
    gi[maxm]={0},ma=0,mi=0,cc[maxm]={0},cnt=0;
int cmp(const use&x,const use&y){return x.di>y.di;}
void add(int u,int v,int vv){
    next[++tot]=point[u];point[u]=tot;en[tot]=v;va[tot]=vv;
    next[++tot]=point[v];point[v]=tot;en[tot]=u;va[tot]=vv;
}
void pre(int u,int ff,int vv){
    int i,j,v;fa[u][0]=ff;
    gi[u]=gi[ff]+vv;dep[u]=dep[ff]+1;
    for (i=1;i<up;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
    for (i=point[u];i;i=next[i]){
        if ((v=en[i])==ff) continue;
        pre(v,u,va[i]);
    }
}
int lca(int u,int v){
    int i;if (dep[u]<dep[v]) swap(u,v);
    for (i=up-1;i>=0;--i)
      if (dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    if (u==v) return u;
    for (i=up-1;i>=0;--i)
      if (fa[u][i]!=fa[v][i]){
        u=fa[u][i];v=fa[v][i];
      }return fa[u][0];
}
int dfs(int u,int ff){
    int i,j,v,sum;sum=cc[u];cc[u]=0;
    for (i=point[u];i;i=next[i]){
        if ((v=en[i])==ff) continue;
        sum+=dfs(v,u);
    }if (sum==cnt) mi=max(mi,gi[u]-gi[fa[u][0]]);
    return sum;
}
int main(){
    int n,m,i,j,u,v,vv,l,r,mid;
    scanf("%d%d",&n,&m);
    for (i=1;i<n;++i){scanf("%d%d%d",&u,&v,&vv);add(u,v,vv);}
    pre(1,0,0);
    for (i=1;i<=m;++i){
        scanf("%d%d",&u,&v);
        ask[i].u=u;ask[i].v=v;ask[i].lc=lca(u,v);
        ask[i].di=gi[ask[i].u]-gi[ask[i].lc]+gi[ask[i].v]-gi[ask[i].lc];
        ma=max(ma,ask[i].di);
    }l=0;r=ma;sort(ask+1,ask+m+1,cmp);
    while(l<r){
        mid=l+r>>1;cnt=mi=i=0;
        while(ask[++i].di>mid&&i<=m){
            ++cc[ask[i].u];++cc[ask[i].v];
            cc[ask[i].lc]-=2;++cnt;
        }dfs(1,0);
        if (ma-mi<=mid) r=mid;
        else l=mid+1;
    }printf("%d\n",l);
}

这样可以做到nlogn,但是会被卡常数。听说网上有一种n的做法。(LL内的排序可以做到n,基数排序思想。)

总的来说,noip2015比2014进步了很多,没有出现实现上的失误,但是有一些想到的没有实现出来,失去了一些分数,还是有些可惜;还有一些思路上的失误;对于时间的把控还应加强。

时间: 2024-10-05 17:17:54

noip2015 总结的相关文章

[NOIP2015] 跳石头

2107. [NOIP2015] 跳石头 ★   输入文件:2015stone.in   输出文件:2015stone.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选 择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石(不含起点和终 点的岩石).在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达 终点. 为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛

树链剖分-Hello!链剖-[NOIP2015]运输计划-[填坑]

This article is made by Jason-Cow.Welcome to reprint.But please post the writer's address. http://www.cnblogs.com/JasonCow/ [NOIP2015]运输计划    Hello!链剖.你好吗? 题意: 给出一棵n个节点的带权树,m对树上点对 现在允许删除一条边,(权值修改为0) 输出: 最小化的点对间最大距离 1.链剖 2.树上差分 3.二分 链剖我就不多说了,就是两dfs 注意

Openjudge NOI题库 ch0111/10 河中跳房子|NOIP2015 day2 stone

这题同时也是NOIP2015 D2T1 跳石头 stone 原题. 总时间限制: 1000ms 内存限制: 65536kB 描述 每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一个岩石跳到另一个岩石.这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点L远 (1 ≤ L≤ 1,000,000,000) 的终点处均有一个岩石.在起点和终点之间,有N (0 ≤ N ≤ 50,000) 个岩石,每个岩石与起点的距离分别为Di (0 < Di < L). 在比赛过程中,奶牛轮流从起点

[NOIP2015]信息传递

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

BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去.显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰.为了鼓励科技创新, L

NOIP2015 运输计划(二分+LCA+差分)

4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status][Discuss] Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui

NOIP2015总结

  Noip2015提高组总结 Noip2015如风般就过去(风一样的美男子),只留下我们在那里暗自神伤. Day0 坐在车上,看着外面的风景,一想到明天就要被屠宰,我的心情是崩溃的.但幸好,车上有位师兄(代号:红薯)开了热点,我的心情向好的方向前进了一大半(他的流量也用去了一大半). 到了之后,欢乐时间(开房时间)就来了,我们打打uno,下下飞行棋,很快时间就到了11点多,然后我就和XWZ洗洗睡了(超刺激). Day1 然后我就要进入屠宰场了,有两位貌似是中大集训队的师姐来监考,我感觉像是喝醉

【NOIP2015】斗地主

P2431 - [NOIP2015]斗地主 Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种 使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如 下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每 次可以根据规定的牌型进行出牌,首先打光自

NOIP2015子串[序列DP]

题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重 叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数

NOIP2015 资料引索

学OI后,发现资料的集合实在是太欠缺了,所以便弄了个引索.如果大家还有更多资源,不妨私信. (陆续更新中,等分数线出后便不再更新) 链接: http://pan.baidu.com/s/1o6CLiH0 密码: cpag 文件浏览: 1.NOIP2015_Junior.pdf[普及试题](来源:老师) 2.NOIP2015_day1.pdf与NOIP2015_day2.pdf[提高试题](来源:老师) 3.SH-Junior.zip[上海普及组选手程序](来源:百度ID:mark001103)