NOIP2017游记 rgnoH

Day -???

考前的几场比赛都打得比较稳定,感觉人品被用光了。突然对NOIP比较害怕。感觉会出现一些莫名其妙的错误。

然后就立了个flag。


Day 0

去巴蜀看了考场,今年的键盘比较舒服,座位不是去年的塑料凳子了,好评。
进了考场打了各种图论和数论板子,最后和PWJ大佬打了个最小表示法。我还记得大佬一开始还没有打对。最后还玩了金山打字通,总的来说感觉心情不是很紧张。


Day 1

这一天活活把AK丢啦。

很早就来到了巴蜀,但是比较疲倦,非常想要睡觉。然后考试时非常受影响。

看到T1就很爽了:这不是O(1)结论题吗?输出 abab 注意一个long long就好了。一分钟100分到手。
T2一看就是暴力恶心模拟,由于个人觉得代码能力有点弱,先看的T3。

T3看数据范围:K<=50!瞬间想出正解:最短路+记忆化搜索!但是突然看到可能有无穷多的方案,虽然只有三组数据,但是心里有点慌。先敲了最短路部分和记忆化搜索计数部分,而且第一次没有敲对,心态有点崩:T3这么简单,不会是想错了吧?反正时间还很充裕,先敲T2。

然后T2敲了1h(最后还是错的),头脑已经很不清醒了。还好T3想出了正解:只有边权全是0的环才可能造成无穷解的情况:因为在零环上跑多少圈,都不会增加dis值。否则已经会增加dis值,只会有有限解。求零环,可以新建一个只有零权边的图,Tarjan判环即可。

无穷解的条件:

MinDis(1,x)+MinDis(x,N)MinDis(1,N)+K,x

敲完过了大样例,心情很愉快。还剩20min左右,然而当时今本上难以思考了,竟然没有检查出T2的错误。

下午睡了个觉,突然发现T2有个地方处理得有问题,最坏情况下只有30分,心态有些凄凉,但是并没有崩。

D1这么简单,D2岂不是……

期望得分230~300。


Day 2

这一天爆炸了。

T1一看,就是判断一个连通性,并查集 O(n2) 即可水过。看到数据范围略大,几乎全用了double。

T2数据范围这么小,不是状压就是搜。但是感觉上更像一个状压DP。然而一开始对状态一点想法都没有。上了两趟厕所才有思路。然而考后发现定的是一个错误的状态,但心想问题不大,至少过40分,更何况这么小的数据一般都能骗很高的分。

T3一看就是一道数据结构题,但是并没有想到怎么做。主要是因为没有写过动态开点,根本没往这方面想。看到空间范围心态爆炸,敲了个50分骗分(而且20分的骗分忘开long long GG)。

最后民间数据测的时候发现T1写错了一个细节,心态爆炸。

期望得分……不敢想了。


出成绩的时候爽死了:虽然分数并不是很高,但是骗到了很多分。最后得分100+90+100+60+80+30=460。

还是有些遗憾,毕竟D2T1这么水的题都没有A掉。今年省选压力可能会比较大,接下来的东西非常多,要好好努力才行。


最后附上两天T3的AC代码:

D1T3 最短路+Tarjan+记忆化搜索:

#include<cstdio>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#define ll long long
#define MAXN 100005
#define MAXM 200005
using namespace std;

int N,M,K;
ll P,f[MAXN][55];
bool INF;

int en[MAXM],las[MAXN],nex[MAXM],len[MAXM],tot;
void Add(int x,int y,int z)
{
    en[++tot]=y;
    nex[tot]=las[x];
    las[x]=tot;
    len[tot]=z;
}

int EN[MAXM],LAS[MAXN],NEX[MAXM],LEN[MAXM],TOT;
void ADD(int x,int y,int z)
{
    EN[++TOT]=y;
    NEX[TOT]=LAS[x];
    LAS[x]=TOT;
    LEN[TOT]=z;
}

int zen[MAXM],zlas[MAXN],znex[MAXM],ztot;
void Zadd(int x,int y)
{
    zen[++ztot]=y;
    znex[ztot]=zlas[x];
    zlas[x]=ztot;
}

queue<int>Q;
int dis[MAXN];
bool mark[MAXN];

void SPFA(int s)
{
    int i,y,x;

    for(i=1;i<=N;i++)dis[i]=1e9;
    Q.push(s);dis[s]=0;

    while(Q.size())
    {
        x=Q.front();Q.pop();mark[x]=false;
        for(i=LAS[x];i;i=NEX[i])
        {
            y=EN[i];
            if(dis[y]>dis[x]+LEN[i])
            {
                dis[y]=dis[x]+LEN[i];
                if(!mark[y])mark[y]=true,Q.push(y);
            }
        }
    }
}

queue<int>_Q;
int _dis[MAXN];
bool _mark[MAXN];

void _SPFA(int s)
{
    int i,y,x;

    for(i=1;i<=N;i++)_dis[i]=1e9;
    _Q.push(s);_dis[s]=0;

    while(_Q.size())
    {
        x=_Q.front();_Q.pop();_mark[x]=false;
        for(i=las[x];i;i=nex[i])
        {
            y=en[i];
            if(_dis[y]>_dis[x]+len[i])
            {
                _dis[y]=_dis[x]+len[i];
                if(!_mark[y])_mark[y]=true,_Q.push(y);
            }
        }
    }
}

ll GetAns(int x,int k)
{
    if(~f[x][k])return f[x][k];

    if(x==N)
    {
        if(k==0)return 1;
        //return 0;
    }

    int i,j,y,t;
    ll Ans=0;

    for(i=las[x];i;i=nex[i])
    {
        y=en[i];t=len[i]-(dis[x]-dis[y]);
        if(t>=0&&t<=k)Ans=(Ans+GetAns(y,k-t))%P;
    }

    return f[x][k]=Ans;
}

stack<int>S;
bool In[MAXN];
int VT,dfn[MAXN],low[MAXN];

void Tarjan(int x)
{
    low[x]=dfn[x]=++VT;
    In[x]=true;
    S.push(x);

    int i,y,cnt=0;
    bool tmp=false;

    for(i=zlas[x];i;i=znex[i])
    {
        y=zen[i];
        if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
        else if(In[y])low[x]=min(low[x],dfn[y]);
    }

    if(dfn[x]!=low[x])return;
    do
    {
        cnt++;
        y=S.top();S.pop();In[y]=false;
        if(dis[y]+_dis[y]<=dis[1]+K)tmp=true;
    }while(x!=y);
    if(cnt>1&&tmp)INF=true;
}

void Clear()
{
    memset(las,0,sizeof(las));
    memset(LAS,0,sizeof(LAS));
    memset(zlas,0,sizeof(zlas));
    memset(f,-1,sizeof(f));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    tot=TOT=ztot=0;INF=false;
}

int main()
{
    int T,i,x,y,z;
    ll Ans;

    scanf("%d",&T);

    while(T--)
    {
        Clear();Ans=0;

        scanf("%d%d%d%lld",&N,&M,&K,&P);
        for(i=1;i<=M;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            Add(x,y,z);ADD(y,x,z);
            if(z==0)Zadd(x,y);
        }

        _SPFA(1);
        SPFA(N);
        for(i=1;i<=N;i++)if(!dfn[i])Tarjan(i);

        if(INF)
        {
            puts("-1");continue;
        }

        for(i=0;i<=K;i++)Ans=(Ans+GetAns(1,i))%P;

        printf("%lld\n",Ans);
    }
}

D2T3 动态开点线段树

#include<stdio.h>
#include<vector>
#define MAXN 1000005
#define MAXM 1000005
#define MAXT 12000005
#define ll long long
using namespace std;

int N,M,Q;
vector<ll>G[MAXN];

ll tot,rt[MAXN],ls[MAXT],rs[MAXT],sum[MAXT];

void Update(int p)
{
    sum[p]=sum[ls[p]]+sum[rs[p]];
}

int Ins(int l,int r)
{
    sum[++tot]=r-l+1;
    return tot;
}

int GetAns(int p,int l,int r,int k)
{
    if(l==r)return l;

    int mid=l+r>>1,ans;
    if(!ls[p])ls[p]=Ins(l,mid);
    if(!rs[p])rs[p]=Ins(mid+1,r);

    if(sum[ls[p]]>=k)ans=GetAns(ls[p],l,mid,k);
    else ans=GetAns(rs[p],mid+1,r,k-sum[ls[p]]);

    return ans;
}

void Sub(int p,int l,int r,int k)
{
    if(l==r){sum[p]--;return;}
    int mid=l+r>>1;
    if(k<=mid)Sub(ls[p],l,mid,k);
    else Sub(rs[p],mid+1,r,k);
    Update(p);
}

int main()
{
    ll Ans,x,y,id;
    int T;

    scanf("%d%d%d",&N,&M,&Q);
    T=Q;
    rt[0]=Ins(1,N+Q);
    for(int i=1; i<=N; i++)rt[i]=Ins(1,M+Q);

    while(T--)
    {
        scanf("%lld%lld",&x,&y);

        if(y<M)
        {
            id=GetAns(rt[x],1,M+Q,y);
            if(id<=M-1)Ans=1ll*(x-1)*M+id;
            else Ans=G[x][id-M];
            Sub(rt[x],1,M+Q,id);

            printf("%lld\n",Ans);

            G[0].push_back(Ans);
            id=GetAns(rt[0],1,N+Q,x);
            if(id<=N)Ans=1ll*id*M;
            else Ans=G[0][id-N-1];
            G[x].push_back(Ans);
            Sub(rt[0],1,N+Q,id);
        }

        else
        {
            id=GetAns(rt[0],1,N+Q,x);
            if(id<=N)Ans=1ll*id*M;
            else Ans=G[0][id-N-1];
            printf("%lld\n",Ans);
            Sub(rt[0],1,N+Q,id);
            G[0].push_back(Ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值