fzu1704(高斯消元法解异或方程组+高精度输出)

题目链接:https://vjudge.net/problem/FZU-1704

题意:经典开关问题,求使得灯全0的方案数。

思路:题目保证至少存在一种方案,即方程组一定有解,那么套上高斯消元法的板子,求出自由变元的个数t,方案总数即2t,t可能大于64,要用到高精度计算。

AC代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

int compare(string str1,string str2){
    int len1=str1.length(),len2=str2.length();
    if(len1<len2)
        return -1;
    else if(len1>len2)
        return 1;
    else
        return str1.compare(str2);
}

//高精度加法,只能是两个正数相加
string add(string str1,string str2){
    string str;
    int len1=str1.length(),len2=str2.length();
    if(len1<len2)
        for(int i=1;i<=len2-len1;i++)
            str1="0"+str1;
    else
        for(int i=1;i<=len1-len2;i++)
            str2="0"+str2;
    int cf=0,tmp;
    len1=str1.length();
    for(int i=len1-1;i>=0;i--){
        tmp=str1[i]-‘0‘+str2[i]-‘0‘+cf;
        cf=tmp/10;
        tmp%=10;
        str=char(tmp+‘0‘)+str;
    }
    if(cf)
        str="1"+str;
    return str;
}

//高精度减法,只能是两个正数相减,而且要大减小
string sub(string str1,string str2){
    string str;
    int len1=str1.length(),len2=str2.length();
    for(int i=1;i<=len1-len2;i++)
        str2="0"+str2;
    int cf=0;
    for(int i=len1-1;i>=0;i--){
        if(str1[i]-cf>=str2[i]){
            str=char(str1[i]-cf-str2[i]+‘0‘)+str;
            cf=0;
        }
        else{
            str=char(str1[i]-cf-str2[i]+10+‘0‘)+str;
            cf=1;
        }
    }
    str.erase(0,str.find_first_not_of(‘0‘));
    if(str.empty())
        str="0";
    return str;
}
//高精度乘法,只能是两个正数相乘
string mul(string str1,string str2){
    string str;
    int len1=str1.length(),len2=str2.length();
    for(int i=len2-1;i>=0;i--){
        string tmpstr;
        int tmp=str2[i]-‘0‘,cf=0,t;
        if(tmp){
            for(int j=1;j<=len2-1-i;j++)
                tmpstr+="0";
            for(int j=len1-1;j>=0;j--){
                t=(tmp*(str1[j]-‘0‘)+cf)%10;
                cf=(tmp*(str1[j]-‘0‘)+cf)/10;
                tmpstr=char(t+‘0‘)+tmpstr;
            }
            if(cf)
                tmpstr=char(cf+‘0‘)+tmpstr;
        }
        str=add(str,tmpstr);
    }
    str.erase(0,str.find_first_not_of(‘0‘));  //删除前面多余的0,因为如果是0×10,结果将会是00
    if(str.empty())
        str="0";
    return str;
}
//高精度除法,只能是两个正数相除
void div(string str1,string str2,string& con,string &rem){
    if(str2=="0")
        return;
    else if(str1=="0"){
        con="0",rem="0";
        return;
    }
    else if(compare(str1,str2)<0){
        con="0",rem=str1;
        return;
    }
    else if(compare(str1,str2)==0){
        con="1",rem="0";
        return;
    }
    else{
        int len1=str1.length(),len2=str2.length();
        string tmpstr;
        for(int i=0;i<len2-1;i++)
            tmpstr=tmpstr+str1[i];
        for(int i=len2-1;i<len1;i++){
            tmpstr=tmpstr+str1[i];
            tmpstr.erase(0,tmpstr.find_first_not_of(‘0‘));
            if(tmpstr.empty())
                tmpstr="0";
            for(char j=‘9‘;j>=‘0‘;j--){
                string str,tmp;
                str=str+j;
                tmp=mul(str,str2);
                if(compare(tmp,tmpstr)<=0){
                    con=con+j;
                    tmpstr=sub(tmpstr,tmp);
                    break;
                }
            }
        }
        rem=tmpstr;
    }
    con.erase(0,con.find_first_not_of(‘0‘));
    if(con.empty())
        con="0";
} 

bool JudgeZero(string s1){
    for(int i=0;i<s1.length();++i)
        if(s1[i]!=‘0‘) return false;
    return true;
}

string gcd(string a,string b){
    if(!JudgeZero(b)){
        string s1,s2;
        div(a,b,s1,s2);
        return gcd(b,s2);
    }
    return a;
}

string lcm(string a,string b){
    string t=gcd(a,b),s1,s2;
    a=mul(a,b);
    div(a,t,s1,s2);
    return s1;
}
const int maxn=105;
int T,equ,var,a[maxn][maxn],x[maxn];

int Gauss(){
    int k=0,max_r;
    for(int col=0;k<equ&&col<var;++k,++col){
        max_r=k;
        for(int i=k+1;i<equ;++i){
            if(abs(a[i][col])>abs(a[max_r][col]))
                max_r=i;
        }
        if(max_r!=k){
            for(int i=col;i<var+1;++i)
                swap(a[max_r][i],a[k][i]);
        }
        if(!a[k][col]){
            --k;
            continue;
        }
        for(int i=k+1;i<equ;++i){
            if(!a[i][col]) continue;
            for(int j=col;j<var+1;++j)
                a[i][j]^=a[k][j];
        }
    }
    for(int i=k;i<equ;++i)
        if(a[i][var])
            return -1;
    return var-k;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&equ,&var);
        for(int i=0;i<equ;++i)
            for(int j=0;j<var+1;++j)
                a[i][j]=0;
        for(int i=0;i<var+1;++i)
            x[i]=0;
        for(int i=0;i<equ;++i)
            scanf("%d",&a[i][var]);
        for(int i=0;i<var;++i){
            int t1,t2;
            scanf("%d",&t1);
            while(t1--){
                scanf("%d",&t2);
                --t2;
                a[t2][i]=1;
            }
        }
        int t=Gauss();
        string s1,s2;
        s1=s1+"1",s2=s2+"2";
        while(t--)
            s1=mul(s1,s2);
        cout<<s1<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/11781060.html

时间: 2024-10-29 04:21:26

fzu1704(高斯消元法解异或方程组+高精度输出)的相关文章

【POJ1222】EXTENDED LIGHTS OUT 高斯消元、解异或方程组

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43481693"); } 题意: 多组数据. 有个5*6的图,然后你要对某些位置进行操作,使得最后灯的状态如图. 操作:这个灯位置的上下左右以及自己这五盏灯状态都取反. 然后输出操作. 说实话什么亮灭什么我全都没考虑. 直接瞎写一遍就PE了,

【BZOJ3503】【Cqoi2014】和谐矩阵 高斯消元,解异或方程组

#include <stdio.h> int main() { puts("转载请注明出处"); puts("地址:blog.csdn.net/vmurder/article/details/43699831"); } 题解: 随便搞搞就好. 自由元全当成1就好了么~~~ 不会异或方程组的移步这里[POJ1222]EXTENDED LIGHTS OUT 高斯消元.解异或方程组 代码: #include <cstdio> #include &l

BZOJ 3563 DZY Loves Chinese / BZOJ 3569 DZY Loves Chinese II 随机化+高斯消元解异或方程组

题目大意:给出一个无向图,问删掉k条边的时候,图是否联通. 思路:虽然我把这两个题放在了一起,但是其实这两个题可以用完全不同的两个解法来解决. 第一个题其实是DZY出错了...把每次的边数也异或了,那就直接用这个性质一个一个往后推就行了..最后一个暴力求一下.. 第二个题才是本意啊. 听到做法的时候我惊呆了.. 首先是将整个图中拆出一个树,那么所有边就分为树边和非树边.将所有非树边都加一个随机权值.树边的权值是所有能够覆盖它的非树边的权值的异或和. 把整个图拆开的充要条件是拆掉一条树边,同时将所

高斯消元法求解异或方程组: cojs.tk 539.//BZOJ 1770 牛棚的灯

高斯消元求解异或方程组: 比较不错的一篇文章:http://blog.sina.com.cn/s/blog_51cea4040100g7hl.html cojs.tk  539. 牛棚的灯 ★★☆   输入文件:lights.in   输出文件:lights.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 贝希和她的闺密们在她们的牛棚中玩游戏.但是天不从人愿,突然,牛棚的电源跳闸了,所有的灯都被关闭了.贝希是一个很胆小的女生,在伸手不见拇指的无尽的黑暗中,她感到惊

【BZOJ2466】【中山市选2009】树 高斯消元解异或方程组

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44356273"); } 题解: 参照此题解,也是我写的,俩题一样. [POJ1681]Painter's Problem 高斯消元,求最小∑系数的异或方程组 代码: #include <cmath> #include &

Hdu 5833 Zhu and 772002(高斯消元解异或方程组)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5833 思路: 将每个数质因数分解,若该位质因数指数为偶数,则该位a[i]为0,否则该位a[i]为1(记a[i]为质因数分解后第i个质数所对应值). 合法方案为积的各位质因子个数对应值a[i]异或值为0. 例3=3^1,4=2^2,则3*3*4对应: 2           3 0   (1 xor 1=0) 则可列方程组 a11x1+a12x2+...+a1nxn=0 a21x1+a22x2+...

高斯消元求解异或方程组

POJ1830 开关问题 对于解异或方程组,系数可以采用二进制压缩,如果系数太多可以使用bitset,但是如果少一点就可以使用下述的写法,更加简单快速 使用bitset的写法更正常的没什么区别,只是对应的消除变为异或操作,另外行变换也会更加简单 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[100

【poj1830-开关问题】高斯消元求解异或方程组

第一道高斯消元题目~ 题目:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态.对于任意一个开关,最多只能进行一次开关操作.你的任务是,计算有多少种可以达到指定状态的方法.(不计开关操作的顺序)0<=N<=29 我们用样例来模拟一下: 我的高斯消元求解异或方程组模版: 1 int gauss

【HDU 5833】Zhu and 772002(异或方程组高斯消元)

300个最大质因数小于2000的数,选若干个它们的乘积为完全平方数有多少种方案. 合法方案的每个数的质因数的个数的奇偶值异或起来为0. 比如12=2^2*3,对应的奇偶值为01(2的个数是偶数为0,3的个数是奇数为1),3的对应奇偶值为01,于是12*3是完全平方数. 然后异或方程组就是: a11x1+a12x2+...+a1nxn=0 a21x1+a22x2+...+a2nxn=0 ... an1x1+an2x2+...+annxn=0 aij:第i个质数(2000内有303个质数)在第j个数