• Luogu P3825 [NOI2017]游戏


    这道题看上去NPC啊,超级不可做的样子。

    我们先分析一下简单的情形:没有(x)地图

    此时每个地图由于限制掉一种汽车,那么显然只会有两种选择。

    再考虑到限制的情况,那么大致做法就很显然了——2-SAT

    首先是拆点,对于每张地图(i)拆成(2i-1)(2i)表示这张地图选择能用的车的第一辆还是第二辆。

    比如如果(s_i=b),那么(2i-1)表示选择(A)车,(2i)表示选择(B)车。

    现在开始考虑选择的限制,对于每一个限制((u,x,v,y)),我们分情况讨论:

    • (s_u=x),说明这个限制没有意义,直接无视即可。
    • (s_u ot=x)(s_v=y)时,说明这时(u)是绝对不能选(x)对应的点的。为了在建图中体现出来我们直接从(x)对应的点向另一个点连边即可。
    • (s_u ot=x)(s_v ot= y)时,显然讲(x)对应的点向(y)对应的点连边。但是不要忘了2-SAT建图的对称性,我们还要从(y)对应的点的反点(x)对应的点的反点连边。这样的意义也十分明确了吧,因为每个地图都必须做出选择,选择(y)对应的点的反点就使得(u)没有其他选择了。

    然后就是用TarjanSCC的过程了,这里不再赘述。值得一提的是Tarjan的标号顺序是按照拓扑序的逆序(因为是DFS)跑出来的,所以可以直接用标号来输出方案。

    那么接下来就是考虑万恶的(x)地图了

    我们发现这样并没有什么好的建图方法,然后翻到下面一看数据范围(dle8)

    然后一种特别naive的想法就是(3^d)枚举每个(x)地图是什么类型。然后再乘上Tarjan的复杂度直接爆炸。

    我们想一下我们枚举的本质:

    • 如果对于一个(x)地图取(a)即意味这只能用车(B,C)
    • 如果对于一个(x)地图取(b)即意味这只能用车(A,C)
    • 如果对于一个(x)地图取(c)即意味这只能用车(A,B)

    然后我们惊奇地发现第三种情况已经被前两种情况包含掉了,所以复杂度变为(2^d(n+m))

    如果对于爆搜会被无解的数据卡满的同志们可以直接随机跑,实测这样也可以过。

    不过实践的时候细节巨多,还是挺烦人的。

    CODE

    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #define RI register int
    #define Ms(f,x) memset(f,x,sizeof(f))
    using namespace std;
    const int N=50005;
    struct ques
    {
        int x,y; char p1,p2;
    }q[N<<1]; int n,m,d,tot,c[N],ukn[10],pt; char ch;
    inline int T(char ch)
    {
        if (ch>='a'&&ch<='c') return ch-'a'+1;
        else return ch-'A'+1;
    }
    inline int Id(int x,int y)
    {
        switch (x)
        {
            case 1:return y!=3?1:0;break;
            case 2:return y!=3?1:0;break;
            case 3:return y!=2?1:0;break;
        }
    }
    inline char C(int x,int y)
    {
        switch (x)
        {
            case 1:return y!=2?'B':'C';break;
            case 2:return y!=2?'A':'C';break;
            case 3:return y!=2?'A':'B';break;
        }
    }
    class FileInputOutput
    {
        private:
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define S 1<<21
            char Fin[S],Fout[S],*A,*B; int Ftop;
        public:
            FileInputOutput() { Ftop=0; A=B=Fin; }
            inline void gc(char &ch)
            {
                while (!isalpha(ch=tc()));
            }
            inline void pc(char ch) 
            { 
                Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch);
            }
            inline void read(int &x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef S
            #undef tc
    }F;
    class Two_SAT_Solver
    {
        private:
            #define add(x,y) e[++cnt]=(edge){y,head[x]},head[x]=cnt
            struct edge
            {
                int to,next;
            }e[N<<2]; int head[N<<1],cnt,dfn[N<<1],low[N<<1],scc,col[N<<1],stack[N<<1],top,tot; bool vis[N];
            inline int min(int a,int b)
            {
            	return a<b?a:b;
            }
            #define to e[i].to
            inline void Tarjan(int now)
            {
            	dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1;
            	for (RI i=head[now];i;i=e[i].next)
            	if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);
            	else if (vis[to]) low[now]=min(low[now],dfn[to]);
            	if (low[now]==dfn[now])
            	{
            		col[now]=++scc; vis[now]=0; while (stack[top]!=now)
            		col[stack[top]]=scc,vis[stack[top--]]=0; --top;
            	}
            }
            #undef to
        public:
            inline void build(void)
            {
                for (RI i=1;i<=m;++i)
                {
                    int x=q[i].x,y=q[i].y,p1=T(q[i].p1),p2=T(q[i].p2);
                    if (c[x]==p1) continue; int numx=x<<1,numy=y<<1;
                    if (c[y]==p2) add(numx-Id(c[x],p1),numx-(Id(c[x],p1)^1)); else 
                    add(numx-Id(c[x],p1),numy-Id(c[y],p2)),add(numy-(Id(c[y],p2)^1),numx-(Id(c[x],p1)^1));
                }
            }
            inline void check(void)
            {
                RI i; int lim=n<<1; for (i=1;i<=lim;++i) if (!dfn[i]) Tarjan(i);
                for (i=1;i<=n;++i) if (col[(i<<1)-1]==col[i<<1]) return;
                for (i=1;i<=n;++i) if (col[(i<<1)-1]<col[i<<1]) F.pc(C(c[i],1)); else F.pc(C(c[i],2));
                F.Fend(); exit(0);
            }
            inline void clear(void)
            {
                cnt=tot=scc=0; Ms(head,0); Ms(dfn,0);
            }
    }S;
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i,j; for (F.read(n),F.read(d),i=1;i<=n;++i) 
        {
            F.gc(ch); if (ch!='x') c[i]=T(ch); else ukn[++pt]=i;
        }
        for (F.read(m),i=1;i<=m;++i) F.read(q[i].x),F.gc(q[i].p1),F.read(q[i].y),F.gc(q[i].p2);
        for (tot=(1<<d)-1,i=0;i<=tot;++i)
        {
            for (j=1;j<=d;++j) c[ukn[j]]=((i>>j-1)&1)+1;
            S.build(); S.check(); S.clear();
        }
        return F.pc('-'),F.pc('1'),F.Fend(),0;
    }
    
  • 相关阅读:
    SQL SERVER 2005添加用户和编辑sa
    数组型参数和数组的区别
    Oracle数据库建库、建表空间,建用户
    oracle表空间操作详解
    Oracle10g的完全卸载(转载)
    Delphi format的用法
    AnImateWindow用法
    文本文件操作
    TStringList的用法
    Delphi网络函数
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9812134.html
Copyright © 2020-2023  润新知