近期离线赛真题T3

来源:互联网 发布:淘宝客 链接 内部跳转 编辑:程序博客网 时间:2024/05/19 17:26

总之考试时基本上是可以A掉的啦

NOIP2012 Day2 T3 疫情控制

分析

无法控制疫情的情况:军队数小于第二层节点数
二分是必然的。
然后贪心向上也是可以明显看出的。
问题就转换为了有哪些点需要通过根节点到另一个第二层节点上。
考虑所有能到达首都的军队,记录他们上来的位置以及其余剩的时间。
然后DFS求出仍需驻扎军队的第二层节点与其到根节点的距离。

那么问题就转换为一个二分图匹配
经测试直接跑二分图匹配理论40实际90
不过这个二分图匹配是可以贪心的,
排序+堆,特判回到原节点就能通过了。
复杂度为O(nlognlogS)
因为调用了系统堆导致跑得慢。

std中采用预留的方法来去掉回原节点的情况,就可以排序贪心了。

代码

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define M 50004#define Mk 16int n,m;int Next[M<<1],V[M<<1],W[M<<1],Head[M],tot;int Pos[M],Cnt,MxSe;void Add_Edge(int u,int v,int w){    Next[++tot]=Head[u],V[Head[u]=tot]=v,W[tot]=w;}#define LREP(i,A) for(int i=Head[A];i;i=Next[i])int Fa[M][Mk],Fr[M];LL Sum[M][Mk],Dis[M],L,R,Ans;void DFS(int A,int f,int From){    Fr[A]=From;    int B;    LREP(i,A)if((B=V[i])!=f){        Fa[B][0]=A;        Sum[B][0]=W[i];        Dis[B]=Dis[A]+W[i];        DFS(B,A,From);    }}struct Node{    int w,x;    bool operator <(const Node &_)const{        return w==_.w?x<_.x:w>_.w;    }};set<Node>S;bool Mark[M];bool Find(int A,int f){    if(Mark[A])return 1;    bool Res=1;    int Son=0,B;    LREP(i,A)if((B=V[i])!=f){        if(!Find(B,A))return 0;        Son++;    }    return Son!=0;}int Tmp[M];LL Less[M];bool Cmp(int a,int b){return Less[a]<Less[b];}bool Check(LL Tim){    memset(Mark,0,sizeof(Mark));    int Num=0;    REP(i,0,m){        int A=Pos[i];        if(Dis[A]>Tim){            LL Tmp=0;            DREP(k,Mk-1,-1)                if(Tmp+Sum[A][k]<=Tim){                    Tmp+=Sum[A][k];                    A=Fa[A][k];                }            Mark[A]=1;        }        else{            Tmp[Num++]=A;            Less[A]=Tim-Dis[A];        }    }    S.clear();    LREP(i,1){        int B=V[i];        if(!Find(B,1))S.insert((Node){Dis[B],B});    }    if(Num<S.size())return 0;    if(S.empty())return 1;    REP(i,0,Num){        int A=Tmp[i];        if(Dis[A]<=Tim){            int f=Fr[A];            LL Les=Less[A];            set<Node>::iterator it,jt;            if(Les>=(*S.begin()).w) it=S.begin();            else{                it=S.lower_bound((Node){Les,0});                if((jt=S.find((Node){Dis[f],f}))!=S.end())                    if(it==S.end() || (*it).w<Dis[f]) it=jt;            }            if(it!=S.end())S.erase(it);        }        if(S.empty())return 1;    }    return S.empty();}void Init(){    REP(k,1,Mk) REP(i,1,n+1){        int j=Fa[i][k-1];        Fa[i][k]=Fa[j][k-1];        Sum[i][k]=Sum[i][k-1]+Sum[j][k-1];    }}int main(){    Rd(n);    REP(i,1,n){        int u,v,w;        Rd(u),Rd(v),Rd(w);        Add_Edge(u,v,w);        Add_Edge(v,u,w);        if(v==1 || u==1)Cnt++;    }    Rd(m);    REP(i,0,m)Rd(Pos[i]);    if(m<Cnt){        puts("-1");        return 0;    }    LREP(i,1){        int B=V[i];        Fa[B][0]=1;        Dis[B]=Sum[B][0]=W[i];        DFS(B,1,B);        chkmax(MxSe,W[i]);    }     REP(i,0,m)chkmax(R,Dis[Pos[i]]);    R+=MxSe;    Fa[1][0]=1;    Init();    while(L<=R){        LL Mid=L+R>>1;        if(Check(Mid))Ans=Mid,R=Mid-1;        else L=Mid+1;    }    printf("%lld\n",Ans);    return 0;}

NOIP2013 Day2 华容道

分析

P60(P70)

容易想到把空格和目标棋子的坐标来作为下标维度来搜索。
简单的BFS就可以完成这种情况下的求解,复杂度为O(qn2m2)

P100

显然对于q=500来说上面的复杂度还是太高了。
注意到每次询问时整个地图的障碍位置是不变的,
而目标棋子移动一位必须要有空格在其四周的一个方向。
预处理出目标棋子在每个可行位置,
空格从其四周某个方向移动到另一个方向的所需步数。
BFS完成,复杂度为O(4n2m2)
然后对于每个询问,先处理出空格移动到目标棋子四个方向的步数。
然后从其开始求最短路,此时点数为O(4nm),边数为O(16nm)
Dij或SPFA均可顺利通过。

代码

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define M 31int n,m,C[M][M],q;bool Check(int x,int y){    return x>0 && y>0 && x<=n && y<=m && C[x][y];}int Xr[]={1,0,0,-1},Yr[]={0,1,-1,0};struct P60{    int Dis[M][M][M][M];    int ex,ey,sx,sy,tx,ty;    struct Node{        int ex,ey,sx,sy;    };    queue<Node>Q;    void Solve(){        while(q--){            Rd(ex),Rd(ey),Rd(sx),Rd(sy),Rd(tx),Rd(ty);            memset(Dis,-1,sizeof(Dis));            while(!Q.empty())Q.pop();            Dis[ex][ey][sx][sy]=0;            Q.push((Node){ex,ey,sx,sy});            bool Flag=0;            while(!Q.empty()){                Node T=Q.front();Q.pop();                int X1=T.ex,Y1=T.ey,X2=T.sx,Y2=T.sy;                int u=Dis[X1][Y1][X2][Y2];                if(X2==tx && Y2==ty){                    printf("%d\n",u);                    Flag=1;                    break;                }                REP(g,0,4){                    int pex=X1+Xr[g],pey=Y1+Yr[g],psx=X2,psy=Y2;                    if(!Check(pex,pey))continue;                    if(pex==X2 && pey==Y2)psx=X1,psy=Y1;                    int &Pos=Dis[pex][pey][psx][psy];                    if(Pos==-1){                        Pos=u+1;                        Q.push((Node){pex,pey,psx,psy});                    }                }            }            if(!Flag)puts("-1");        }    }}P60;struct P100{    int Len[M][M][4][4];//4,4:原来空格的方向,现在空格的方向。     int Dis[M][M];    int Ans[M][M][4];    bool No[M][M];    int Qx[M*M],Qy[M*M];     void BFS(int sx,int sy){        int l,r;        l=r=0;        memset(Dis,-1,sizeof(Dis));        Dis[sx][sy]=0;        Qx[r]=sx,Qy[r++]=sy;        while(l<r){            int X1=Qx[l],Y1=Qy[l++];            REP(g,0,4){                int X2=X1+Xr[g],Y2=Y1+Yr[g];                if(!Check(X2,Y2) || No[X2][Y2])continue;                if(Dis[X2][Y2]==-1){                    Dis[X2][Y2]=Dis[X1][Y1]+1;                    Qx[r]=X2,Qy[r++]=Y2;                }            }        }    }    void Init(){        memset(Len,-1,sizeof(Len));        REP(x,1,n+1) REP(y,1,m+1){            if(!Check(x,y))continue;            No[x][y]=1;            REP(g,0,4){                int px=x+Xr[g],py=y+Yr[g];                if(!Check(px,py))continue;                BFS(px,py);                REP(k,0,4){                    int xp=x+Xr[k],yp=y+Yr[k];                    if(!Check(xp,yp))continue;                    if(Dis[xp][yp]==-1)continue;                    Len[x][y][g][k]=Dis[xp][yp];                }            }            No[x][y]=0;        }    }    int ex,ey,sx,sy,tx,ty;    struct Node{        int x,y,p,w;        bool operator <(const Node &_)const{            return w>_.w;        }    };    priority_queue<Node>Q;    void Solve(){        Init();        while(q--){            Rd(ex),Rd(ey),Rd(sx),Rd(sy),Rd(tx),Rd(ty);            if(sx==tx && sy==ty){                puts("0");                continue;            }            No[sx][sy]=1;            BFS(ex,ey);            No[sx][sy]=0;            while(!Q.empty())Q.pop();            memset(Ans,63,sizeof(Ans));            REP(g,0,4){                int px=sx+Xr[g],py=sy+Yr[g];                if(!Check(px,py))continue;                if(Dis[px][py]!=-1){                    Ans[sx][sy][g]=Dis[px][py];                    Q.push((Node){sx,sy,g,Dis[px][py]});                }            }            bool Flag=0;            while(!Q.empty()){                Node T=Q.top();Q.pop();                int x=T.x,y=T.y,p=T.p,w=T.w;                if(w!=Ans[x][y][p])continue;                if(x==tx && y==ty){                    printf("%d\n",w);                    Flag=1;                    break;                }                REP(g,0,4){                    if(Len[x][y][p][g]==-1)continue;                    int px=x+Xr[g],py=y+Yr[g],pp=3-g,Cost=w+Len[x][y][p][g]+1;                    if(Cost<Ans[px][py][pp]){                        Ans[px][py][pp]=Cost;                        Q.push((Node){px,py,pp,Cost});                    }                }            }            if(!Flag)puts("-1");        }    }}P100;int main(){    Rd(n),Rd(m),Rd(q);    REP(i,1,n+1) REP(j,1,m+1) Rd(C[i][j]);    if(q<=10)P60.Solve();    else P100.Solve();    return 0;}

NOIP2015 Day1 T3 斗地主

这道破题的题意十分鬼畜超越了普通斗地主的玩法
所幸数据很良心并没有什么特别的情况

分析

看这个数据范围和保证随机,
说明这是一道搜索题。
然后因为这道题的牌型很多,分类考虑。
定义Fi,j,k,l为打出i个单张,j个对子,k个三张,l个四张
所需的最小步数。
那么状态数很小,然后转移起来比较简单。
稍微注意一下拆掉对子三张四张的情况。
剩下的就枚举顺子连对之类的东西然后直接DFS吧。
速度很快。
另:似乎机房没有人写DP..

代码

如果把王炸当对子(原题就这么打的)算的话把那些多余的东西删掉即可。

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define LL long long#define INF 0x3f3f3f3fint T,n,P[16];int F[24][24][24][24];void Init(){    memset(F,63,sizeof(F));    F[0][0][0][0]=0;    REP(l,0,8) REP(k,0,10) REP(j,0,18) REP(i,0,18){        int &Now=F[i][j][k][l];        if(i) chkmin(Now,F[i-1][j][k][l]+1);        if(j) chkmin(Now,F[i][j-1][k][l]+1);        if(k) chkmin(Now,F[i][j][k-1][l]+1);         if(l) chkmin(Now,F[i][j][k][l-1]+1);        if(k && i) chkmin(Now,F[i-1][j][k-1][l]+1);        if(k && j) chkmin(Now,F[i][j-1][k-1][l]+1);        if(l && i>=2) chkmin(Now,F[i-2][j][k][l-1]+1);        if(l && j>=2) chkmin(Now,F[i][j-2][k][l-1]+1);        if(j) chkmin(Now,F[i+2][j-1][k][l]);//拆对子        if(k) chkmin(Now,F[i+1][j+1][k-1][l]);//拆三张         if(l) chkmin(Now,F[i+1][j][k+1][l-1]);//拆炸弹         if(l) chkmin(Now,F[i][j+2][k][l-1]);    }}int Ans;void Solve(int Type,int S){    if(S>Ans)return;    int Cnt[6];    memset(Cnt,0,sizeof(Cnt));    REP(i,0,15)Cnt[P[i]]++;    chkmin(Ans,F[Cnt[1]][Cnt[2]][Cnt[3]][Cnt[4]]+S);    if(Type<=1){        REP(i,3,14){            int j=i,len=0;            while(j<15 && P[j]>=3){                P[j++]-=3,len++;                if(len>=2)Solve(1,S+1);            }            REP(k,i,j)P[k]+=3;        }    }    if(Type<=2){        REP(i,3,13){            int j=i,len=0;            while(j<15 && P[j]>=2){                P[j++]-=2,len++;                if(len>=3)Solve(2,S+1);            }            REP(k,i,j)P[k]+=2;        }    }    if(Type<=3){        REP(i,3,11){            int j=i,len=0;            while(j<15 && P[j]>=1){                P[j++]--,len++;                if(len>=5)Solve(3,S+1);            }            REP(k,i,j)P[k]++;        }    }}int main(){    scanf("%d %d",&T,&n);    Init();    while(T--){        memset(P,0,sizeof(P));        REP(i,0,n){            int a,b;            scanf("%d %d",&a,&b);            if(a==1)a=14;            if(a==0)a=b-1;            P[a]++;        }        Ans=INF;        Solve(1,0);        int Res=Ans;        if(P[0] && P[1]){            P[0]=P[1]=0;            Ans=INF;            Solve(1,0);            chkmin(Res,Ans+1);        }        printf("%d\n",Res);    }    return 0;}

2017-10-26.RT..