P3825 [NOI2017]游戏

题目链接:https://www.luogu.com.cn/problem/P3825

我太蠢了呀。

题意读错想半天。蠢的跟猪一样。

最后看了题解才晓得题意读错了,猪,你为何这么蠢。

先来个题意知识:

小 L 对游戏有一些特殊的要求,这些要求可以用四元组 (i,hi,j,hj)来描述,表示若在第i场使用型号为hi的车子,则第j场游戏要使用型号为hj的车子。

这句话的意思应该是在第i场选择了hi的时候,则第j场必须选择hj。

但是是建了反向边的呢?也就是说: 若两个都可用,则从i向j连边,表示若选i,则一定选j,同时从j′向i′连边,这里表示若没有选j,则一定没有选i。

为啥没有选hj,则i那个位置不能选hi呢?题目只是说i选择了hi,则j必须选择hj呀。我相信有部分同学会有这个困惑。

解释:

如何证明原命题与其逆否命题具有相同的真假性,请给出证明
用反证法
设原命题为“若p则q”,则逆否命题为“若非q则非p”
假设“原命题与其逆否命题具有相同的真假性”错误
则有“若p→q为真,则 非q→非p为假”
或“若p→q为假,则 非q→非p为真”
1,若p→q为真,则 非q→非p为假
因为非q→非p为假,所以非q→p为真 这与 p→q为真 矛盾
2,若p→q为假,则 非q→非p为真
因为p→q为假,所以p→非q为真 这与 非q→非p为真 矛盾
所以假设均不成立,所以原命题与其逆否命题具有相同的真假性,得证.
反证法成立的原理就是逆否命题和原命题等价?
你瞎说什么呢.
反证法是排除其它一切可能,只剩这一种可能,和逆否命题和原命题等价一点关系都没有的好吧
证明链接:https://www.zybang.com/question/2622b4d2c390a64ddaee7580b5b23ac5.html
这里主要是原命题和逆否命题的知识;
我们考虑一下当d为0的时候:
那么,每个地图最多会有两辆车子。而且每个地图一定是会从中选取一辆车。
那这也就是一个2-SAT问题的模板了。只是说我们要仔细考虑。
如果xi地图为B,则i表示选择A车,i+n表示选择C车
如果地图为C,则i表示选择A车,i+n表示选择B车
如果地图为A,则i表示选择B车,i+n表示选择C车。
考虑建边问题:
对于一个四元组(i,hi,j,hj)
如果str[i]==hi,则表示地图i中,根本不可能选择hi这辆车,那这个直接continue就好。
在上面条件不满足情况下,如果str[j]==hj,则表示,j这个位置一定不可以选择hj这辆车。那么我们可以把i和i+n进行连接,表示如果i这个位置选择了hi,则也一定要选择i’。
在上面条件都不满足情况下,也就是说i这个为位置可以选择hi,j这个位置可以选择hj。
那我肯定要i指向j的位置。同时因为逆否命题,我要j'指向i'这个位置。
然后观察得到d值较小。我们可以直接枚举每个X位置会为什么情况。
理论上,我们需要枚举每个x位置分别为A,B,C 的情况
也就是:
1,x位置为A,则可选车为B和C
2,x位置为B,则可选车为A和C
3,x位置为C,则可选车为A和B
我们可以发现,第一种和第二种其实已经包含了第三种。
所以我们只要枚举两种情况即可。
    #include"stdio.h"
    #include"string.h"
    #include"vector"
    #include"algorithm"
    using namespace std;
    #define OK printf("\n");
    #define exit return 0;
    const int N = 1e6 * 2 + 1010;
    const int M = 2 * N;
    int read()
    {
        int f=1,x=0;
        char ss=getchar();
        while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
        while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
        return f*x;
    }
    int head[N],ver[M],Next[M],tot;int n,m,num,top,cnt;
    int dfn[N],low[N],id[110];int limit = 0;
    int Stack[N],ins[N],c[N];
    int s[N];  char str[N];
    int X[N],Y[N]; char cx[N],cy[N];

    void add(int x,int y){
        ver[++ tot] = y; Next[tot] = head[x];
        head[x] = tot;
    }

    void tarjan(int x){
        dfn[x] = low[x] = ++ num;
        Stack[++ top] = x; ins[x] = 1;
        for(int i = head[x]; i; i = Next[i])
            if(!dfn[ver[i]]) {
                tarjan(ver[i]);
                low[x] = min(low[x],low[ver[i]]);
            } else if(ins[ver[i]])
             low[x] = min(low[x],dfn[ver[i]]);
        if(dfn[x] == low[x]){
            cnt ++; int y;
            do{
                y = Stack[top --];ins[y] = 0;
                c[y] = cnt;
            } while(x != y);
        }
    }

    void Build_edge()
    {
       for(int i = 1; i <= m; i ++){
            if(str[X[i]] == cx[i]) continue;
            if(str[Y[i]] == cy[i]) {
                if(cx[i] == 'C' || (cx[i] == 'B' && str[X[i]] == 'C')) {
                   add(X[i] + n,X[i]); //printf("%d -> %d\n",X[i] + n,X[i]);
                } else {
                    add(X[i],X[i] + n); //printf("%d -> %d\n",X[i],X[i] + n);
                }
                continue;
            }
            int v1 = (cy[i] == 'C' || (cy[i] == 'B' && str[Y[i]] == 'C')) ? 1 : 0;
            int v2 = (cx[i] == 'C' || (cx[i] == 'B' && str[X[i]] == 'C')) ? 1 : 0;
            add(X[i] + n * (v2),Y[i] + n * v1);
            add(Y[i] + n * (v1 ^ 1),X[i] + n * (v2 ^ 1));
           // printf("%d -> %d\n",X[i] + n *(v2),Y[i] + n * v1);
          //  printf("%d -> %d\n",Y[i] + n * (v1 ^ 1),X[i] + n * (v2 ^ 1));
        }
        return ;
    }
    void init()
    {
        num = 0; memset(ins,0,sizeof(ins));
        cnt = 0; tot = 0; top = 0;
        memset(low,0,sizeof(low)); memset(c,0,sizeof(c));
        memset(dfn,0,sizeof(dfn));memset(Stack,0,sizeof(Stack));
        memset(head,0,sizeof(head));
    }
    void solve(){

        int mark = 1;
        for(int i = 0; i < (1 << limit); i ++){
            init();mark = 1;
            for(int j = 1; j <= limit; j ++){
                str[id[j]] = (i & (1 << (j - 1))) ? 'A' : 'B';
            }
            Build_edge();
            for(int i = 1; i <= n * 2; i ++){
                if(!dfn[i]) tarjan(i);
            }
            for(int i = 1; i <= n; i ++)
              if(c[i] == c[i + n]) {mark = 0; break;}
            if(mark == 0) continue;
            for(int i = 1; i <= n; i ++){
                if(c[i] < c[i + n]){
                    if(str[i] == 'A') printf("B");
                    else printf("A");
                } else {
                    if(str[i] == 'C') printf("B");
                    else printf("C");
                }
            }
            return ;
        }
        printf("-1"); return ;
    }
    int main()
    {
        int d;
        scanf("%d%d",&n,&d);
        scanf("%s",str + 1);
        for(int i = 1; i <= n; i ++)
         {
             if(str[i] == 'x') id[++ limit] = i;
             else str[i] -= 32;
         }
        m = read();
        for(int i = 1; i <= m; i ++){
           scanf("%d %c %d %c",&X[i],&cx[i],&Y[i],&cy[i]);
        }
        solve();
        return 0;
    }

 

 

posted @ 2020-03-06 18:11  风生  阅读(151)  评论(0编辑  收藏  举报