fzu1704(高斯消元法解异或方程组+高精度输出)
Posted frankchen831x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于fzu1704(高斯消元法解异或方程组+高精度输出)的主要内容,如果未能解决你的问题,请参考以下文章
hdu 5755 Gambler Bo (高斯消元法解同余方程组)
bzoj千题计划187:bzoj1770: [Usaco2009 Nov]lights 燈 (高斯消元解异或方程组+枚举自由元)