zoukankan      html  css  js  c++  java
  • [NOI2011]

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    省选完挂。但是善良的教练今天丢了一套NOI2011给我们训练 6道题233(虽然一道题做过了,一道题普及组的都会,就算是4道吧)

    熬了一天,总算啃掉了四题中的三题 D2T3那个牛逼的博弈论实在不知道怎么做,只好去看看题解233

    简单讲一下题解..

    D1T1兔农

    农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到隔壁的小朋友在讨论兔子繁殖的问题。

    问题是这样的:第一个月初有一对刚出生的小兔子,经过两个月长大后,这对兔子从第三个月开始,每个月初生一对小兔子。新出生的小兔子生长两个月后又能每个月生出一对小兔子。问第n个月有多少只兔子?

    聪明的你可能已经发现,第n个月的兔子数正好是第n个Fibonacci(斐波那契)数。栋栋不懂什么是Fibonacci数,但他也发现了规律:第i+2个月的兔子数等于第i个月的兔子数加上第i+1个月的兔子数。前几个月的兔子数依次为:

    1 1 2 3 5 8 13 21 34 …

    栋栋发现越到后面兔子数增长的越快,期待养兔子一定能赚大钱,于是栋栋在第一个月初买了一对小兔子开始饲养。

    每天,栋栋都要给兔子们喂食,兔子们吃食时非常特别,总是每k对兔子围成一圈,最后剩下的不足k对的围成一圈,由于兔子特别害怕孤独,从第三个月开始,如果吃食时围成某一个圈的只有一对兔子,这对兔子就会很快死掉。

    我们假设死去的总是刚出生的兔子,那么每个月的兔子数仍然是可以计算的。例如,当k=7时,前几个月的兔子数依次为:

    1 1 2 3 5 7 12 19 31 49 80 …

    给定n,你能帮助栋栋计算第n个月他有多少对兔子么?由于答案可能非常大,你只需要告诉栋栋第n个月的兔子对数除p的余数即可。

    1s/256MB   n<=10^18 k<=10^6 p<=10^9

    上来就刚这道题 但是不会.. 仔细想想没有那么复杂

    在一个点从1变成0之后,假设这个1之前的数字是x,之后的序列就变成了x,x,2x,3x,恰好是一个斐波那契数列!

    这种斐波那契数列不同的显然不超过k个,之后就会出现循环节。推到这里,解法就比较显然了。

    先暴力求出斐波那契数列膜k意义下的每个数值最小的出现位置,然后找到第一个1。

    之后我们不断拿出1之前的数字,用exgcd求它下一次变成1的时候,也就是它关于k的逆元,那么它下次出现1的位置就是这个逆元在斐波那契数列的第一次的出现位置。

    我们对一个数求解的时候给它打一个标记,一旦我们找到了已经求解过的数,说明找到了循环节。

    但是我们还要支持-1操作,所以考虑给斐波那契矩阵加一维1.  

    $egin{equation}
    left[
    egin{matrix}
    fi\
    f_{i-1}\
    1
    end{matrix}
    ight]
    end{equation}$*$egin{equation}
    left[
    egin{matrix}
    1&1&0\
    1&0&0\
    0&0&1&
    end{matrix}
    ight]
    end{equation}$=$egin{equation}
    left[
    egin{matrix}
    f_{i+1}\
    fi\
    1
    end{matrix}
    ight]
    end{equation}$

    $egin{equation}
    left[
    egin{matrix}
    fi\
    f_{i-1}\
    1
    end{matrix}
    ight]
    end{equation}$*$egin{equation}
    left[
    egin{matrix}
    1&0&-1\
    0&1&0\
    0&0&1&
    end{matrix}
    ight]
    end{equation}$=$egin{equation}
    left[
    egin{matrix}
    fi-1\
    f_{i-1}\
    1
    end{matrix}
    ight]
    end{equation}$

    用这两个矩阵就可以求出循环节的转移矩阵,然后直接快速幂就行啦。

    一开始没想到要加一维 后来乱改 应该是我写的最丑的代码之一..

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #define ll long long
    #define MN 2000000
    using namespace std;
    inline ll read()
    {
        ll x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    ll n;
    int K,p,f[MN+5],mp[1000005];
    ll L[1000005];
    bool flag=0;
    
    struct Matrix 
    {
        int s[4][4];
        Matrix(){memset(s,0,sizeof(s));}
    }A,B,C,D,Mem[1000005];
    
    Matrix Mul(Matrix a,Matrix b,int mod)
    {
        Matrix c;
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
                for(int k=1;k<=3;k++)
                    c.s[i][j]=(c.s[i][j]+1LL*a.s[i][k]*b.s[k][j])%mod;
        return c;    
    }
    
    void Init()
    {
        memset(C.s,0,sizeof(C.s));
        C.s[1][1]=C.s[1][2]=C.s[2][1]=1;
        C.s[2][2]=0;C.s[3][3]=1;
    }
    
    Matrix MatPow(Matrix C,Matrix D,ll k,int mod)
    {
        for(;k;k>>=1,D=Mul(D,D,mod))
            if(k&1) C=Mul(C,D,mod);
        return C;
    }
    
    void vio(Matrix&D,ll k,int mod)
    {
        Init();
        for(;k;k>>=1,C=Mul(C,C,mod))
            if(k&1) D=Mul(C,D,mod);
    }
    
    inline ll exgcd(ll a,ll b,ll&x,ll&y)
    {
        if(!b){x=1;y=0;return a;}
        ll c=exgcd(b,a%b,x,y);
        ll t=x;x=y;y=t-a/b*x;
        return c;    
    }
    
    ll getinv(int x,int mod)
    {
        ll X,Y;
        if(1!=exgcd(x,mod,X,Y)) return 0; 
        return (X%mod+mod)%mod;
    }
    
    inline void Dec(Matrix&D)
    {
        memset(A.s,0,sizeof(A.s));
        A.s[1][1]=A.s[2][2]=A.s[3][3]=1;A.s[1][3]=p-1;  
        D=Mul(A,D,p);
        B.s[1][1]=0;
    }
    
    Matrix GetSq(int x)
    {
        Matrix E;int y=x;
        E.s[1][1]=E.s[2][2]=E.s[3][3]=1;
        do 
        {
            ll z=getinv(y,K);z=mp[z];
            vio(E,z,p);vio(B,z,K);Dec(E);
            y=B.s[2][1];
        }while(y!=x);
        return E;
    }
    
    void Solve(int x)
    {
        if(!n) return;
        if(L[x]) {ll tms=n/(L[x]-n);
                    if(tms)
                    {
                        Matrix T=GetSq(x);
                        T=MatPow(T,T,tms-1,p);
                        D=MatPow(T,D,1,p);
                    }n%=(L[x]-n);
                    flag=true;return;}
        L[x]=n;Mem[x]=D;ll y;
        if(!(y=getinv(x,K))) return;
        y=mp[y];if(y>n) return;
        n-=y;
        vio(D,y,p);vio(B,y,K);
    //    B.print();
        Dec(D);Solve(B.s[2][1]);
    }
    
    int main()
    {
        f[1]=f[2]=1;B.s[1][1]=B.s[2][1]=D.s[1][1]=D.s[2][1]=B.s[3][1]=D.s[3][1]=1;
        n=read();K=read();p=read();
        for(int i=3;i<=MN;i++) f[i]=(f[i-1]+f[i-2])%K;
        for(int i=3;i<=MN;i++) if(!mp[f[i]]) mp[f[i]]=i;
        if(!mp[1]||mp[1]>n) return vio(D,max(0LL,n-2),p),0*printf("%d
    ",D.s[1][1]); 
        vio(D,mp[1]-2,p);vio(B,mp[1]-2,K);n-=mp[1];Dec(D);
        Solve(B.s[2][1]);
        if(flag) 
        {
            memset(L,0,sizeof(L));
            Solve(B.s[2][1]);    
        } 
        vio(D,n,p);printf("%d
    ",D.s[1][1]);
        return 0;
    }

    D1T2 智能车比赛

    新一届智能车大赛在JL大学开始啦!比赛赛道可以看作是由n个矩形区域拼接而成(如下图所示),每个矩形的边都平行于坐标轴,第i个矩形区域的左下角和右上角坐标分别为(xi,1,yi,1)和(xi,2,yi,2)。

    题目保证:xi,1<xi,2=xi+1,1,且yi,1< yi,2,相邻两个矩形一定有重叠在一起的边(如图中虚线所示),智能车可以通过这部分穿梭于矩形区域之间。

    给定速度(意义不明)求起点到终点的最短时间。

    1s/256MB n<=2000

    发现到达的点一定是矩形的点,然后直接n^2dp就行了  计算几何比较烦

    但是我菜,写了建图最短路,差点T了,大家还是学学dp做法吧,比我的优很多...

    代码蛮贴一贴

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    #define pa pair<double,int> 
    #define mp(x,y) make_pair(x,y)
    #define MN 8005
    #define FROM 8002
    #define TO 8001
    #define eps 1e-7
    #define INF 2000000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    inline double sqr(double x){return x*x;}
    struct P
    {
        double x,y;    
        P(double _x=0,double _y=0):x(_x),y(_y){}
        double operator^(const P&b){return x*b.y-y*b.x;}
        P operator-(const P&b){return P(x-b.x,y-b.y);}
        friend double dis(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));} 
    }S,T;
    int U[MN+5],D[MN+5],X[MN+5];
    struct L
    {    
        P p,v;
        L(){}
        L(P a,P b):p(a),v(b){}
        bool Left(P x){return (v^(x-p))>-eps;}
        bool Right(P x){return (v^(x-p))<eps;}
    };
    struct edge{int to,next;double f;}e[MN*100+5];
    double v,d[MN+5];
    int n,cnt=0,head[MN+5];
    priority_queue<pa,vector<pa>,greater<pa> >q;
    inline void ins(int f,int t,double w)
    {
    //    cout<<"ins"<<f<<" "<<t<<" "<<w<<endl;
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],w};head[t]=cnt;
    }
    
    void SolveLeft(int R,int from,P x)
    {
        L up(x,P(0,INF)),down(x,P(0,-INF));
        for(register int i=R;~i;--i)
        {
            P u=P(X[i],U[i]),d=P(X[i],D[i]); 
            if(up.Left(u)&&down.Right(u))
                ins(from,n+1+i,dis(u,x));
            if(up.Left(d)&&down.Right(d))
                ins(from,i,dis(d,x));
            if(up.Left(u)) up=L(x,u-x);
            if(down.Right(d)) down=L(x,d-x);
        }
    }
    
    void SolveRight(int Le,int from,P x)
    {
        L up(x,P(0,INF)),down(x,P(0,-INF));
        for(register int i=Le;i<=n;++i)
        {
            P u=P(X[i],U[i]),d=P(X[i],D[i]); 
            if(up.Right(u)&&down.Left(u))
                ins(from,n+1+i,dis(u,x));
            if(up.Right(d)&&down.Left(d))
                ins(from,i,dis(d,x));
            if(up.Right(u)) up=L(x,u-x);
            if(down.Left(d)) down=L(x,d-x);
        }
    }
    
    void dij()
    {
        memset(d,127,sizeof(d));d[FROM]=0;
        q.push(mp(0,FROM));
        while(!q.empty())
        {
            while(!q.empty()&&q.top().first!=d[q.top().second]) q.pop();
            if(q.empty()) break;
            int x=q.top().second;q.pop();
            for(int i=head[x];i;i=e[i].next)
                if(e[i].f+d[x]<d[e[i].to])
                {
                    d[e[i].to]=d[x]+e[i].f;
                    q.push(mp(d[e[i].to],e[i].to));    
                }
        }
    }
    
    int main()
    {
        n=read();
        U[0]=INF;D[0]=-INF;
        for(register int i=1;i<=n;i++)
        {
            int x1=read(),y1=read(),x2=read(),y2=read();
            X[i-1]=x1;X[i]=x2;
            U[i-1]=min(U[i-1],y2);
            D[i-1]=max(D[i-1],y1);
            U[i]=y2;D[i]=y1;
        }
        S.x=read();S.y=read();T.x=read();T.y=read();
        for(register int i=0;i<=n;i++)
        {
            if(i) SolveLeft(i-1,n+1+i,P(X[i],U[i])),
                  SolveLeft(i-1,i,P(X[i],D[i]));    
            if(i<n) SolveRight(i+1,n+1+i,P(X[i],U[i])),
                    SolveRight(i+1,i,P(X[i],D[i]));
        }
        register int i=0,j=0;bool flag=1;
        for(;X[i]<S.x;++i);    
        for(;X[j]<T.x;++j);
        flag&=(i==j);
        if(X[i]==S.x)
        { 
            ins(i,FROM,dis(P(X[i],D[i]),S)),ins(i+n+1,FROM,dis(S,P(X[i],U[i])));
            if(S.y>=D[i]&&S.y<=U[i]&&i>0) 
                if(i>0)SolveLeft(i-1,FROM,S);
        }
        else if(i>0)SolveLeft(i-1,FROM,S);
        for(;X[i]==S.x;++i);if(i<n)SolveRight(i,FROM,S);
        if(X[j]==T.x) 
        {
            ins(j,TO,dis(T,P(X[j],D[j]))),ins(j+n+1,TO,dis(T,P(X[j],U[j])));
            if(T.y>=D[j]&&T.y<=U[j]&&j>0) 
                if(j>0)SolveLeft(j-1,TO,T);
        }
        else if(j>0)SolveLeft(j-1,TO,T);
        for(;X[j]==T.x;++j);if(j<n)SolveRight(j,TO,T);
        dij();double v;scanf("%lf",&v);    
        if(i==j&&flag) d[TO]=min(d[TO],dis(S,T));
        printf("%.10lf
    ",d[TO]/v);
        return 0;
    }

    D1T3阿狸的打字机 

    以前做的题目 戳这里

    D2T1道路修建

    在 W 星球上有 n 个国家。为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通。但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 条双向道路。 每条道路的修建都要付出一定的费用,这个费用等于道路长度乘以道路两端 的国家个数之差的绝对值。例如,在下图中,虚线所示道路两端分别有 2 个、4 个国家,如果该道路长度为 1,则费用为 1×|2 – 4|=2。图中圆圈里的数字表示国 家的编号。

    由于国家的数量十分庞大,道路的建造方案有很多种,同时每种方案的修建 费用难以用人工计算,国王们决定找人设计一个软件,对于给定的建造方案,计 算出所需要的费用。请你帮助国王们设计一个这样的软件。

    n<=1000000  1s/256MB

    普及组水平的题目...

    #include<iostream>
    #include<cstdio>
    #define MN 1000000
    #define ll long long
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
     
    int n,head[MN+5],cnt=0,size[MN+5];
    struct edge{int to,next,w;}e[MN*2+5];
    ll ans=0;
    inline void ins(int f,int t,int w){e[++cnt]=(edge){t,head[f],w};head[f]=cnt;}
    inline int abs(int x){return x<0?-x:x;}
    void dfs(int x,int f)
    {
        size[x]=1;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=f)
            {
                dfs(e[i].to,x);
                size[x]+=size[e[i].to];
                ans+=1LL*e[i].w*abs(size[e[i].to]-(n-size[e[i].to]));
            }
    }
     
    int main()
    {
        n=read();
        for(int i=1;i<n;i++) 
        {
            int x=read(),y=read(),w=read();
            ins(x,y,w);ins(y,x,w);
        }
        dfs(1,0);
        printf("%lld
    ",ans);
        return 0;
    }

    D2T2 Noi嘉年华

    NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办。每个嘉年华可能包含很多个活动,而每个活动只能在一个嘉年华中举办。

    现在嘉年华活动的组织者小安一共收到了 n个活动的举办申请,其中第 i 个活动的起始时间为 Si,活动的持续时间为Ti。这些活动都可以安排到任意一个嘉年华的会场,也可以不安排。

    小安通过广泛的调查发现,如果某个时刻,两个嘉年华会场同时有活动在进行(不包括活动的开始瞬间和结束瞬间),那么有的选手就会纠结于到底去哪个会场,从而变得不开心。所以,为了避免这样不开心的事情发生,小安要求不能有两个活动在两个会场同时进行(同一会场内的活动可以任意进行)。

    另外,可以想象,如果某一个嘉年华会场的活动太少,那么这个嘉年华的吸引力就会不足,容易导致场面冷清。所以小安希望通过合理的安排,使得活动相对较少的嘉年华的活动数量最大。

    此外,有一些活动非常有意义,小安希望能举办,他希望知道,如果第i 个活动必须举办(可以安排在两场嘉年华中的任何一个),活动相对较少的嘉年华的活动数量的最大值。

    n<=200  1s/256MB

    这道题看起来很可做  但是啃了很久做不出来  还好yy出了一个比较靠谱的dp方程,总算过了  差点忍不住去看题解了233

    离散时间点,然后f[i][j]表示前i个时间点其中一个嘉年华举办j场活动,另一场最多举办几场,转移比较显然。 g[i][j]表示后.....

    令h[i][j]表示时间点i到j的区间最多能办几场活动,那么对于每一个时间段x-y,答案是Ans[x][y]=max(min(f[x-1][i]+h[x][y]+g[y+1][k-i],k)) 后面那一串显然可以二分。

    所以处理完Ans数组之后,每个询问只要去查一个最大值就行了。复杂度n^3logn

    貌似可以借助单调性做到n^3   但是莫名没有我跑的快...

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define MN 400
    #define INF 1000000000 
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    int f[MN+5][MN+5],g[MN+5][MN+5],h[MN+5][MN+5],p[MN+5],Ans[MN+5][MN+5],tot=0,n,m=1;
    struct eve{int b,e;}e[MN+5];
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            e[i].b=read();
            e[i].e=e[i].b+read()-1;    
            p[++tot]=e[i].b;
            p[++tot]=e[i].e;
        }
        sort(p+1,p+tot+1);
        for(int i=2;i<=tot;i++)
            if(p[i]!=p[i-1]) p[++m]=p[i];
        for(int i=1;i<=n;i++)
        {
            e[i].b=lower_bound(p+1,p+m+1,e[i].b)-p;
            e[i].e=lower_bound(p+1,p+m+1,e[i].e)-p;
            h[e[i].b][e[i].e]++;
        } 
        for(int len=2;len<=m;len++)
            for(int i=1;i+len-1<=m;i++)
            {
                int j=i+len-1;
                h[i][j]=h[i][j]+h[i+1][j]+h[i][j-1]-h[i+1][j-1]; 
            }
        for(int i=0;i<=m+1;i++)
            for(int j=0;j<=n;j++) f[i][j]=g[i][j]=-INF;
        f[0][0]=g[m+1][0]=0;
        for(int i=1;i<=m;i++)
            for(int k=0;k<=n;k++)
            {
                for(int j=0;j<i;j++)
                    if(h[j+1][i]<=k)
                        f[i][k]=max(f[i][k],f[j][k-h[j+1][i]]);
                f[i][k]=max(f[i][k],f[i-1][k]);
                if(f[i][k]>=0) f[i][f[i][k]]=max(f[i][f[i][k]],k);
            }
        for(int i=m;i;--i)
            for(int k=0;k<=n;k++)
            {
                for(int j=i+1;j<=m+1;j++)
                    if(h[i][j-1]<=k)
                        g[i][k]=max(g[i][k],g[j][k-h[i][j-1]]);
                g[i][k]=max(g[i][k],g[i+1][k]);
                if(g[i][k]>=0) g[i][g[i][k]]=max(k,g[i][g[i][k]]);
            }            
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,min(i,f[m][i]));
        printf("%d
    ",ans);
        for(int i=0;i<=m;i++)
            for(int j=i+1;j<=m+1;j++)
            {
                int l=1,r=n,ans=0,mid;
                while(l<=r)
                {
                    mid=l+r>>1;bool flag=false;
                    for(int k=0;k<=mid;k++)
                        if(f[i][k]+g[j][mid-k]+h[i+1][j-1]>=mid)
                        {
                            flag=true;
                            break;
                        }
                    if(flag) ans=mid,l=mid+1;
                    else r=mid-1;
                }
                Ans[i][j]=ans;
            }
        for(int i=1;i<=n;i++)
        {
            int ans=0;
            for(int j=0;j<e[i].b;j++)
                for(int k=e[i].e+1;k<=m+1;k++)
                    ans=max(ans,Ans[j][k]);    
            printf("%d
    ",ans);
        }
        return 0;
    }

    D2T3

    这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。 这个游戏是在一个n行m列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。 每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:

    兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格。

    蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格。

    第一个不能按照规则操作的人输掉游戏。为了描述方便,下面将操作“将第x行第y列中的棋子移进空格中”记为M(x,y)。 例如下面是三个游戏的例子。

    最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友——你——来帮助她。她带来了一局输给蛋蛋的游戏的实录,请你指出这一局游戏中所有她“犯错误”的地方。 注意:

    两个格子相邻当且仅当它们有一条公共边。

    兔兔的操作是“犯错误”的,当且仅当,在这次操作前兔兔有必胜策略,而这次操作后蛋蛋有必胜策略。

    丢个链接:这里有很详细的题解 

    #include<cstdio>
    #include<iostream>
    #define MN 1600
    #define MC 40
    using namespace std;
    inline int read()
    {
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int n,m,head[MN+5],cnt=0,match[MN+5],mark[MN+5],fx,fy,s[MC+5][MC+5],tot=0,cn=0,Ans[MN+5];
    struct edge{int to,next;}e[MN*4+5];
    char st[MC+5][MC+5];
    bool ban[MN+5];
    const int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}
    inline int num(int x,int y){return (x-1)*m+y;}
    
    bool Dfs(int x)
    {
        for(int i=head[x];i;i=e[i].next)
            if(mark[e[i].to]!=tot&&!ban[e[i].to])
            {
                mark[e[i].to]=tot;
                if(!match[e[i].to]||Dfs(match[e[i].to]))
                {
                    match[x]=e[i].to;
                    match[e[i].to]=x;
                    return true;
                }
            }
        return false;
    }
    
    int calc(int x)
    {
        ban[x]=1;
        if(!match[x])return 0;
        int rt=match[x];
        match[rt]=match[x]=0;
        return ++tot,!Dfs(rt);
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++) scanf("%s",st[i]+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(st[i][j]=='.') fx=i,fy=j;
                else s[i][j]=st[i][j]=='X'?0:1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                for(int k=0;k<4;k++)
                {
                    int x=i+dis[k][0],y=j+dis[k][1];
                    if(x<1||y<1||x>n||y>m||s[i][j]==s[x][y]) continue;
                    ins(num(i,j),num(x,y));
                }
        for(int i=1;i<=n*m;++i) if(!match[i])++tot,Dfs(i);
        int q=read();
        for(int i=1;i<=q;++i)
        {
            int res1=calc(num(fx,fy));
            fx=read(),fy=read();
            int res2=calc(num(fx,fy));
            if(res1&&res2) Ans[++cn]=i;
            fx=read();fy=read();
        }
        cout<<cn<<endl;
        for(int i=1;i<=cn;i++)printf("%d
    ",Ans[i]);
        return 0;
    }
  • 相关阅读:
    深入理解计算机系统(3.2)---数据格式、访问信息以及操作数指示符
    深入理解计算机系统(3.1)---走进汇编的世界
    linux下的usb抓包方法
    Linux中查看系统资源占用情况的命令
    中药介绍
    shell中的for循环用法详解
    Linux上shell脚本date的用法
    linux下的shell运算(加、减、乘、除)
    [linux time命令学习篇] time 统计命令执行的时间
    一文简述多种强化学习算法,重要概念和术语一览
  • 原文地址:https://www.cnblogs.com/FallDream/p/noi2011.html
Copyright © 2011-2022 走看看