zoukankan      html  css  js  c++  java
  • poj1830 开关问题[高斯消元]

    其实第一反应是双向BFS或者meet in middle,$2^{14}$的搜索量,多测,应该是可以过的,但是无奈双向BFS我只写过一题,已经不会写了。

    发现灯的操作情况顺序不影响结果,因为操作相当于在固定位进行xor运算,xor是可以随便交换的,所以顺序无所谓。

    那么情况取决于每盏灯是否被操作过。设这个量为未知量$x_i$。于是可以设计方程,对于每个灯,有

    $begin ext{xor} x_1 a_{1,1} ext{xor} x_2 a_{2,1} ext{xor} ... ext{xor} x_n a_{n,1} = end$

    就是初始状态经过每一个灯对他的异或(这个异或是灯$i$是否操作乘上灯$i$是否影响这个灯,取$0/1$),最后得最终状态。

    把$begin$初状态移到右边去。仿照高消内容,然后从第一个未知数开始消就行。

    最后要问有多少种方案,也就是有多少个自由元可以随便取$0/1$,那答案就是$2^{自由元个数}$。否则全零系数的等式右边是$1$就无解。

    感谢hkk上午给我讲无穷多解和无解的判断,不然我就要磕一下午了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #define dbg(x) cerr << #x << " = " << x <<endl
     7 using namespace std;
     8 typedef long long ll;
     9 typedef double db;
    10 typedef pair<int,int> pii;
    11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    16 template<typename T>inline T read(T&x){
    17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    19 }
    20 int A[33],bin[33];
    21 int T,n,x,y,c,ans;
    22 
    23 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
    24     for(register int i=0;i<=30;++i)bin[i]=1<<i;
    25     read(T);while(T--){
    26         read(n);ans=0;
    27         memset(A,0,sizeof A);
    28         for(register int i=1;i<=n;++i)read(x),A[i]|=x<<n;
    29         for(register int i=1;i<=n;++i)read(x),A[i]^=x<<n;
    30         while(read(x),read(y))A[y]|=bin[x-1];
    31         for(register int i=1;i<=n;++i)A[i]|=bin[i-1];
    32         for(x=1,c=1;c<=n;++c){//dbg(c),dbg(x),dbg(A[x]);
    33             for(y=x;y<=n&&!(bin[c-1]&A[y]);++y);
    34             if(y==n+1)continue;
    35             swap(A[x],A[y]);
    36             for(register int l=1;l<=n;++l)if((l^x)&&(A[l]&bin[c-1]))A[l]^=A[x];
    37             ++x;
    38         }
    39         for(register int i=x;i<=n;++i){
    40             if(A[i]&bin[n])ans=-114514;
    41             else ++ans;
    42         }
    43         if(ans<0)puts("Oh,it's impossible~!!");
    44         else printf("%d
    ",1<<ans);
    45     }
    46     return 0;
    47 }
    View Code

    Upd:这种题也可以用暴力枚举加小技巧优化来做,lyd书上在比较开头的地方有提到(“费解的开关”这题),复杂度$O(nm2^m)$。

  • 相关阅读:
    【无旋转treap】模板
    线性选择算法好题
    【codeforces】305C GCD,容斥
    双连通
    线段树(3)
    线段树(2)
    线段树
    2015 Multi-University Training Contest 2
    2015 Multi-University Training Contest 1
    Codeforces Round #302 (Div. 1)
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11493189.html
Copyright © 2011-2022 走看看