2017NOIP游记

  记得去年这个时候,大概刚接触OI。没想到时间这么快,第一次2017NOIP之旅已经结束。初测成绩出来了,100+100+95+50=345,有浙江三十几名(@Cptraser 机房370大佬)。总体感觉还可以吧,也发挥的不错。但有些地方还是有点可惜。学校里的学长(@Cptraser)让我开个博客,我也想谨以此记录一下自己的点滴吧。

  贴的都是比赛时的原码

T1 太搞笑的一题,虽然有很多人因为精度爆60(还好手动整数除)

CODE

#include<cstdio>
using namespace std;
int a,b,c;
int main()
{
    freopen("score.in","r",stdin); freopen("score.out","w",stdout);
    scanf("%d%d%d",&a,&b,&c);
    printf("%d",a/5+b*3/10+c/2);
    return 0;
}

 

T2 感觉今年PJ前两题今年来算是最水的吧,刚开始想打字符串的,后来仔细一想%%%一下就水了

CODE

#include<cstdio>
#include<algorithm>
using namespace std;
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
const int N=1005;
int n,q,i,j,x,s[N],w;
inline int Pow_10(int k)
{
    int tot=1;
    for (int i=1;i<=k;++i)
    tot*=10;
    return tot;
}
int main()
{
    freopen("librarian.in","r",stdin); freopen("librarian.out","w",stdout);
    read(n); read(q);
    for (i=1;i<=n;++i)
    read(s[i]);
    sort(s+1,s+n+1);
    for (i=1;i<=q;++i)
    {
        bool flag=0;
        read(w); read(x);
        for (j=1;j<=n;++j)
        if (s[j]%Pow_10(w)==x) { printf("%d\n",s[j]); flag=1; break; }
        if (!flag) puts("-1");
    }
    return 0;
}

 

T3 从T3开始难度就有提升。BFS很简单;SPFA很简单; 然而我考试时都没想到,对着一个记搜调了2个半小时,导致我T4最后想到了单调队列优化然后没时间了

先贴比赛CODE(158行)

#include<cstdio>
#include<cstring>
using namespace std;
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
const int M=105,fx[4]={0,1,0,-1},fy[4]={1,0,-1,0},INF=1e9;
int map[M][M],n,m,i,j,x,y,z,ans=1e9,f[M][M][3],vis[M][M];
inline int min(int a,int b) { return a<b?a:b; }
void dfs(int x,int y)
{
    bool flag=0;
    if (map[x][y]==0) flag=1;
    for (int i=0;i<4;++i)
    {
        int xx=fx[i]+x,yy=fy[i]+y;
        if (xx>0&&xx<=m&&yy>0&&yy<=m&&vis[xx][yy])
        {
            if (map[xx][yy])
            {
                if (f[xx][yy][0]!=INF) 
                {
                    if (flag) 
                    {
                        int add;
                        if (map[xx][yy]==1) add=0; else add=1;
                        f[x][y][1]=min(f[x][y][1],f[xx][yy][0]+add+2);
                        if (map[xx][yy]==2) add=0; else add=1;
                        f[x][y][2]=min(f[x][y][2],f[xx][yy][0]+add+2); 
                    } else
                    {
                        int add;
                        if (map[x][y]==map[xx][yy]) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][0]+add);
                    }
                } else
                {
                    vis[xx][yy]=0;
                    dfs(xx,yy);
                    vis[xx][yy]=1;
                    if (flag) 
                    {
                        int add;
                        if (map[xx][yy]==1) add=0; else add=1;
                        f[x][y][1]=min(f[x][y][1],f[xx][yy][0]+add+2);
                        if (map[xx][yy]==2) add=0; else add=1;
                        f[x][y][2]=min(f[x][y][2],f[xx][yy][0]+add+2); 
                    } else
                    {
                        int add;
                        if (map[x][y]==map[xx][yy]) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][0]+add);
                    }
                }
            } else
            {
                if (f[xx][yy][1]!=INF&&f[xx][yy][2]!=INF)
                {
                    if (!flag) 
                    {
                        int add;
                        if (map[x][y]==1) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][1]+add);
                        if (map[x][y]==2) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][2]+add);
                    } 
                } else 
                { 
                    if (!flag)
                    {
                        vis[xx][yy]=0; 
                        dfs(xx,yy); 
                        vis[xx][yy]=1; 
                        int add;
                        if (map[x][y]==1) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][1]+add);
                        if (map[x][y]==2) add=0; else add=1;
                        f[x][y][0]=min(f[x][y][0],f[xx][yy][2]+add);
                    }
                }
            }
        }
    }
}
void xz()
{
    for (int i=1;i<=m;++i)
    for (int j=1;j<=m;++j)
    {
        if (map[i][j]) 
        {
            for (int k=0;k<4;++k)
            {
                int x=fx[k]+i,y=fy[k]+j;
                if (x>0&&x<=m&&y>0&&y<=m) 
                {
                    if (map[x][y]) 
                    {
                        int add;
                        if (map[x][y]==map[i][j]) add=0; else add=1;
                        f[i][j][0]=min(f[i][j][0],f[x][y][0]+add);
                    } else
                    {
                        int add;
                        if (map[i][j]==1) add=0; else add=1;
                        f[i][j][0]=min(f[i][j][0],f[x][y][1]+add);
                        if (map[i][j]==2) add=0; else add=1;
                        f[i][j][0]=min(f[i][j][0],f[x][y][2]+add);
                    }
                }
            }
        } else
        {
            for (int k=0;k<4;++k)
            {
                int x=fx[k]+i,y=fy[k]+j;
                if (x>0&&x<=m&&y>0&&y<=m)
                {
                    if (map[x][y])
                    {
                        int add;
                        if (map[x][y]==1) add=0; else add=1;
                        f[i][j][1]=min(f[i][j][1],f[x][y][0]+add+2);
                        if (map[x][y]==2) add=0; else add=1;
                        f[i][j][2]=min(f[i][j][2],f[x][y][0]+add+2);
                    }
                }
            }
        }
    }
}
int main()
{
    freopen("chess.in","r",stdin); freopen("chess.out","w",stdout);
    memset(map,0,sizeof(map));
    memset(vis,true,sizeof(vis));
    read(m); read(n);
    for (i=1;i<=m;++i)
    for (j=1;j<=m;++j)
    f[i][j][0]=f[i][j][1]=f[i][j][2]=INF;
    f[1][1][0]=0;
    for (i=1;i<=n;++i)
    {
        read(x); read(y); read(z);
        map[x][y]=z+1;
    }
    vis[m][m]=0;
    dfs(m,m);
    xz();
    bool flag=0;
    if (map[m][m]==0) flag=1;
    if (flag) { if (min(f[m][m][1],f[m][m][2])==INF) puts("-1"); else printf("%d",min(f[m][m][1],f[m][m][2])); }
    else { if (f[m][m][0]==INF) puts("-1"); else printf("%d",f[m][m][0]); }
    return 0;
}

上面的dfs其实在搞笑,真正得(骗)了95分的是那个最后10分钟加上去的xz(),%%%%%%

 

回来后仔细想了想,打了个SPFA,就是建边的过程有点烦

对于每个有颜色的点

距离为1的有颜色的点颜色相同连1条0的边;颜色不同连一条1的边;

距离为2的有颜色的点颜色相同连1条2的边;颜色不同连一条3的边;

最后对于(m,m)有无颜色的问题特判一下就过了,代码量明显减少

CODE

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int fx1[4]={0,1,0,-1},fy1[4]={1,0,-1,0},fx2[8]={0,0,-2,2,-1,-1,1,1},fy2[8]={-2,2,0,0,-1,1,-1,1};
const int M=105;
int map[M][M],INF,father[M*M+10],i,x,y,z,n,m,j,dis[M*M+10],q[M*M*2+10],f[M*M+10],head,tail;
vector <int> a[M*M+10],l[M*M+10];
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
void build(int x,int y)
{
    for (int i=0;i<4;++i)
    {
        int xx=x+fx1[i],yy=y+fy1[i];
        if (map[xx][yy]!=INF&&xx>0&&yy>0&&xx<=m&&yy<=m) 
        a[(x-1)*m+y].push_back((xx-1)*m+yy),l[(x-1)*m+y].push_back(map[x][y]!=map[xx][yy]);
    }
    for (int i=0;i<8;++i)
    {
        int xx=x+fx2[i],yy=y+fy2[i];
        if (map[xx][yy]!=INF&&xx>0&&yy>0&&xx<=m&&yy<=m) 
        a[(x-1)*m+y].push_back((xx-1)*m+yy),l[(x-1)*m+y].push_back(map[x][y]==map[xx][yy]?2:3);
    }
}
int main()
{
    freopen("chess.in","r",stdin); freopen("chess.out","w",stdout);
    read(m); read(n);
    memset(map,63,sizeof(map));
    memset(dis,63,sizeof(dis));
    for (i=1;i<=n;++i)
    {
        read(x); read(y); read(z); 
        map[x][y]=z;
    }
    INF=map[0][0];
    for (i=1;i<=m;++i)
    for (j=1;j<=m;++j)
    if (map[i][j]!=INF) build(i,j);
    dis[1]=0; q[1]=1; f[1]=1;
    head=0; tail=1;
    while (head<tail)
    {
        int now=q[++head];
        f[now]=0;
        for (i=0;i<a[now].size();++i)
        {
            int k=a[now][i];
            if (dis[k]>dis[now]+l[now][i])
            {
                dis[k]=dis[now]+l[now][i];
                if (!f[k])
                {
                    q[++tail]=k;
                    f[k]=1;
                }
            }
        }
    }
    if (map[m][m]==INF) 
    {
        if (map[m][m-1]!=INF) dis[m*m]=min(dis[m*m],dis[m*m-1]+2);
        if (map[m-1][m]!=INF) dis[m*m]=min(dis[m*m],dis[m*m-m]+2);
    }
    if (dis[m*m]==INF) puts("-1"); else printf("%d",dis[m*m]);
    return 0;
}

 

T4 谨记机房大佬(@Cptraser)的教诲,NOIP已经很久很久没有考MST了。然而今年,一如既往的没考。

最后一题 看一眼 二分答案,check()

          再一看 二维DP也许能行 20分钟打好

               然后优化第三题去了 然后再也没有回来

比赛CODE

#include<cstdio>
#include<cstring>
typedef long long LL;
using namespace std;
inline void read(LL &x)
{
    x=0; char ch=getchar(); LL flag=1;
    while (ch<'0'||ch>'9') { if (ch=='-') flag=-1; ch=getchar(); }
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=flag;
}
const LL N=500005;
struct data
{
    LL x,w;
}a[N];
LL n,d,k,i,j,ans=-1,sum=0,f[N];
inline LL max(LL a,LL b) { return a>b?a:b; }
bool check(LL x)
{
    LL left=x<d?d-x:1,right=d+x;
    for (i=1;i<=n;++i)
    f[i]=-1e9;
    for (i=1;i<=n;++i)
    for (j=0;j<i;++j)
    if (a[i].x-a[j].x>=left&&a[i].x-a[j].x<=right) 
    {
        f[i]=max(f[i],f[j]+a[i].w);
        if (f[i]>=k) return 1;
    }
    return 0;
}
int main()
{
    freopen("jump.in","r",stdin); freopen("jump.out","w",stdout);
    read(n); read(d); read(k);    
    for (i=1;i<=n;++i)
    read(a[i].x),read(a[i].w),sum+=a[i].w>0?a[i].w:0;
    if (sum<k) { puts("-1"); return 0; }
    if (d==1)
    {
        sum=0;
        for (i=1;i<=n;++i)
        {
            sum+=a[i].w;
            if (sum>=k) { puts("0"); return 0; }
        }
    }
    a[0].x=a[0].w=0;
    LL l=0,r=a[n].x;
    while (l<=r)
    {
        LL mid=(l+r)>>1;
        if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
    }
    printf("%lld",ans);
    return 0;
}

               那个 d==1 的特判其实是在搞笑

     单调队列的优化还是很好想的

               在距离内的加入,距离外的弹出,为了取最大最优值只需要保持队列单调递减即可。

     借鉴了洛谷一名大佬的思路

CODE

#include<cstdio>
#include<cstring>
typedef long long LL;
using namespace std;
inline void read(LL &x)
{
    x=0; char ch=getchar(); LL flag=1;
    while (ch<'0'||ch>'9') { if (ch=='-') flag=-1; ch=getchar(); }
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=flag;
}
const LL N=500005;
struct data
{
    LL x,w;
}a[N];
struct dl
{
    LL x,s;
}q[N*2+10];
LL n,d,k,i,j,ans=-1,sum=0,f[N],head,tail,now;
inline LL max(LL a,LL b) { return a>b?a:b; }
bool check(LL x)
{
    LL left=x<d?d-x:1,right=d+x;
    for (i=1;i<=n;++i)
    f[i]=-1e9;
    q[0].x=q[0].s=0; head=0; tail=-1; now=0;
    for (i=1;i<=n;++i)
    {
        for (now;(a[now].x<=a[i].x-left)&&(now<i);++now)
        {
            while (head<=tail&&q[tail].s<f[now]) --tail;
            if (f[now]==-1e9) continue;
            q[++tail].x=a[now].x; q[tail].s=f[now];
        }
        while (head<=tail&&a[i].x-q[head].x>right) head++;
        if (head<=tail) f[i]=q[head].s+a[i].w;
        if (f[i]>=k) return 1;
    }
    return 0;
}
int main()
{
    freopen("jump.in","r",stdin); freopen("jump.out","w",stdout);
    read(n); read(d); read(k);    
    for (i=1;i<=n;++i)
    read(a[i].x),read(a[i].w),sum+=a[i].w>0?a[i].w:0;
    if (sum<k) { puts("-1"); return 0; }
    /*if (d==1)
    {
        sum=0;
        for (i=1;i<=n;++i)
        {
            sum+=a[i].w;
            if (sum>=k) { puts("0"); return 0; }
        }
    }*/
    a[0].x=a[0].w=0;
    LL l=0,r=a[n].x;
    while (l<=r)
    {
        LL mid=(l+r)>>1;
        if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
    }
    printf("%lld",ans);
    return 0;
}

 

  暑假才P->C,代码有点chou

  其实今年的O气真的很足,第三题水了95

  感觉今年总体难度比去年低吧,但浙江的分数线才280(据说)……

  有点小兴奋吧,毕竟一年的付出没有白费

  明年再接再厉,准备下提高吧

 

  顺便宣传下大佬的博客(@Cptraser)http://www.cnblogs.com/Cptraser/

 

posted @ 2017-11-23 17:47  空気力学の詩  阅读(677)  评论(7编辑  收藏  举报