开关问题
题意:n个开关n个灯,每个开关负责多个灯,给出灯的初始状态和最终状态,问有多少种摁开关的方案(与顺序无关)。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 const int maxn=35; 6 int a[maxn][maxn],b[maxn]; 7 int n; 8 void gauss_elimination(){ 9 for(int i=0,col=0;i<n-1&&col<=n;){ 10 if(a[i][col]==0){ 11 int r; 12 for(r=i+1;r<n;r++){ 13 if(a[r][col]){ 14 for(int j=col;j<=n;j++){ 15 swap(a[i][j],a[r][j]); 16 } 17 break; 18 } 19 } 20 if(r==n){ //这列下面都为0 21 col++; 22 continue; 23 } 24 } 25 //消元 26 for(int r=i+1;r<n;r++){ 27 if(a[r][col]){ 28 for(int j=col;j<=n;j++){ 29 a[r][j]^=a[i][j]; 30 } 31 } 32 } 33 i++;col++; 34 } 35 } 36 int solve(){ 37 for(int i=0;i<n;i++){ 38 int flag=1; 39 for(int j=0;j<n;j++){ 40 if(a[i][j]) { 41 flag=0; 42 break; 43 } 44 } 45 if(flag){ 46 for(int r=i;r<n;r++){ 47 if(a[r][n]){ 48 return -1; 49 } 50 } 51 return 1<<(n-i); 52 } 53 } 54 return 1; 55 } 56 int main(){ 57 int t; 58 scanf("%d",&t); 59 while(t--){ 60 memset(a,0,sizeof(a)); 61 scanf("%d",&n); 62 for(int i=0;i<n;i++){ 63 scanf("%d",&b[i]); 64 } 65 int e; 66 for(int i=0;i<n;i++){ 67 scanf("%d",&e); 68 b[i]^=e; //1为需要变化 69 } 70 int u,v; 71 while(scanf("%d%d",&u,&v)&&(u||v)){ 72 a[v-1][u-1]=1; 73 } 74 for(int i=0;i<n;i++){ 75 a[i][i]=1; 76 a[i][n]=b[i]; 77 } 78 gauss_elimination(); 79 int ans=solve(); 80 if(ans<0){ 81 puts("Oh,it's impossible~!!"); 82 }else { 83 printf("%d ",ans); 84 } 85 } 86 return 0; 87 }
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <cmath> 5 using namespace std; 6 const int maxn=35; 7 int a[maxn][maxn],b[maxn]; 8 int n; 9 int gauss_elimination(){ 10 int i=0,j=0; 11 while(j<n){ //列主元? 12 int r=i; 13 for(int k=i+1;k<n;k++) 14 if(fabs(a[k][j])>fabs(a[r][j])) r=k; 15 if(r!=i) for(int k=j;k<=n;k++) swap(a[r][k],a[i][k]); 16 if(a[i][j]==0){ j++; continue;} // 17 for(int k=i+1;k<n;k++){ //消元 18 if(a[k][j]==0) continue; 19 for(int col=j;col<=n;col++) a[k][col]^=a[i][col]; 20 } 21 i++;j++; 22 } 23 for(int k=i;k<n;k++){ 24 if(a[k][n]!=0) return -1; 25 } 26 return 1<<(n-i); 27 } 28 29 int main(){ 30 int t; 31 scanf("%d",&t); 32 while(t--){ 33 memset(a,0,sizeof(a)); 34 scanf("%d",&n); 35 for(int i=0;i<n;i++) scanf("%d",&b[i]); 36 int e; 37 for(int i=0;i<n;i++){ 38 scanf("%d",&e); 39 b[i]^=e; //1为需要变化 40 } 41 int u,v; 42 while(scanf("%d%d",&u,&v)&&(u||v)) a[v-1][u-1]=1; 43 44 for(int i=0;i<n;i++){ 45 a[i][i]=1; 46 a[i][n]=b[i]; 47 } 48 int ans=gauss_elimination(); 49 if(ans<0) puts("Oh,it's impossible~!!"); 50 else printf("%d ",ans); 51 } 52 return 0; 53 }
Lanterns
题意:和上一题基本一样,查询多次。
用的更普遍的方法~
模线性方程组高斯消元模板
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int mod=2; 4 const int maxn=55; 5 int a[maxn][maxn],b[maxn][maxn]; 6 int x[maxn]; 7 int n,m; 8 9 int gcd(int a,int b){ 10 return b==0?a:gcd(b,a%b); 11 } 12 int lcm(int a,int b){ 13 int g=gcd(a,b); 14 return a/g*b; 15 } 16 void exgcd(int a,int b,int &d,int &x,int &y){ 17 if(!b){d=a;x=1;y=0;} 18 else {exgcd(b,a%b,d,y,x); y-=x*(a/b);} 19 } 20 21 int gauss(int n,int m){ 22 int r,c; 23 for(r=0,c=0;r<n&&c<m;c++){ 24 int max_r=r; 25 for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i; 26 if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]); 27 if(!a[r][c]) continue; 28 for(int i=r+1;i<n;i++) if(a[i][c]){ 29 int d=lcm(a[i][c],a[r][c]); 30 int t1=d/a[i][c],t2=d/a[r][c]; 31 for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod; 32 } 33 r++; 34 } 35 for(int i=r;i<n;i++) if(a[i][m]) return -1; 36 /* 37 for(int i=r-1;i>=0;i--){ 38 x[i]=a[i][m]; 39 for(int j=i+1;j<m;j++){ 40 x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod; 41 } 42 int x1,y1,d; 43 exgcd(a[i][i],mod,d,x1,y1); 44 x1=((x1%mod)+mod)%mod; 45 x[i]=x[i]*x1%mod; 46 } 47 */ 48 return m-r; 49 } 50 51 int main(){ 52 int t,kase=0; 53 scanf("%d",&t); 54 while(t--){ 55 printf("Case %d: ",++kase); 56 memset(a,0,sizeof(a)); 57 memset(b,0,sizeof(b)); 58 scanf("%d%d",&n,&m); 59 int k; 60 for(int i=0;i<m;i++){ 61 scanf("%d",&k); 62 int u; 63 while(k--){ 64 scanf("%d",&u); 65 b[u-1][i]=1; 66 } 67 } 68 int q; 69 scanf("%d",&q); 70 while(q--){ 71 for(int i=0;i<n;i++) scanf("%d",&a[i][m]); 72 for(int i=0;i<n;i++){ 73 for(int j=0;j<m;j++) 74 a[i][j]=b[i][j]; 75 } 76 int ans=gauss(n,m); 77 if(ans==-1) puts("0"); 78 else printf("%lld ",(1ll<<ans)); 79 } 80 } 81 return 0; 82 }
gcd写错了竟然过了,,结果下一道题坑了好久=_=||
EXTENDED LIGHTS OUT
题意:还是开关~
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=33; 7 int a[maxn][maxn]; 8 int x[maxn]; 9 10 void init(int n,int m){ 11 for(int i=0;i<n;i++){ 12 for(int j=0;j<m;j++){ 13 int num=i*m+j; 14 a[num][num]=1; 15 if(i!=0) a[num-m][num]=1; 16 if(i!=n-1) a[num+m][num]=1; 17 if(j!=0) a[num-1][num]=1; 18 if(j!=m-1) a[num+1][num]=1; 19 } 20 } 21 } 22 void gauss(int n,int m){ 23 int r,c; 24 for(r=0,c=0;r<n&&c<m;c++){ 25 int max_r=r; 26 for(int i=r+1;i<n;i++) if(a[i][c]>a[max_r][c]) max_r=i; 27 if(max_r!=r) for(int j=c;j<=m;j++) swap(a[max_r][j],a[r][j]); 28 if(a[r][r]==0) continue; 29 for(int i=r+1;i<n;i++){ 30 if(a[i][c]==0) continue; //!!! 31 for(int j=c;j<=m;j++) a[i][j]^=a[r][j]; 32 } 33 r++; 34 } 35 //题目说了有唯一解 36 for(int i=n-1;i>=0;i--){ 37 x[i]=a[i][30]; 38 for(int j=i+1;j<m;j++) if(a[i][j]) x[i]^=x[j]; 39 } 40 return; 41 } 42 int main(){ 43 int t; 44 int kase=0; 45 scanf("%d",&t); 46 while(t--){ 47 printf("PUZZLE #%d ",++kase); 48 memset(a,0,sizeof(a)); 49 for(int i=0;i<30;i++) scanf("%d",&a[i][30]); 50 init(5,6); 51 gauss(30,30); 52 int id=0; 53 for(int i=0;i<5;i++){ 54 for(int j=0;j<6;j++) { 55 printf("%d%c",x[id++],j==5?' ':' '); 56 } 57 } 58 } 59 return 0; 60 }
Painter's Problem
题意:开关=_=||
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int inf=0x3f3f3f3f; 7 const int maxn=16; 8 int a[maxn*maxn][maxn*maxn]; 9 int x[maxn],fx[maxn]; 10 11 int gauss(int n,int m){ 12 int r,c; 13 int num=0; 14 for(r=0,c=0;r<n&&c<m;c++){ 15 int max_r=r; 16 for(int i=r+1;i<n;i++) if(a[i][c]>a[r][c]) max_r=i; 17 if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]); 18 if(a[r][r]==0) {fx[num++]=c;continue;} 19 for(int i=r+1;i<n;i++){ 20 if(a[i][c]==0) continue; 21 for(int j=c;j<=m;j++) a[i][j]^=a[r][j]; 22 } 23 r++; 24 } 25 for(int i=r;i<n;i++) if(a[i][m]) return -1; 26 int sta=1<<(m-r); 27 int res=inf; 28 for(int i=0;i<sta;i++){ 29 int cnt=0; 30 int id=i; 31 for(int j=0;j<num;j++){ 32 x[fx[j]]=(id&1); 33 if(x[fx[j]]) cnt++; 34 id>>=1; 35 } 36 for(int j=r-1;j>=0;j--){ 37 x[j]=a[j][m]; 38 for(int k=j+1;k<m;k++) if(a[j][k]) x[j]^=x[k]; 39 if(x[j]) cnt++; 40 } 41 if(cnt<res) res=cnt; 42 } 43 return res; 44 } 45 void init(int n){ 46 for(int i=0;i<n;i++){ 47 for(int j=0;j<n;j++){ 48 int num=i*n+j; 49 a[num][num]=1; 50 if(i!=0) a[num-n][num]=1; 51 if(i!=n-1) a[num+n][num]=1; 52 if(j!=0) a[num-1][num]=1; 53 if(j!=n-1) a[num+1][num]=1; 54 } 55 } 56 } 57 int main(){ 58 int t; 59 scanf("%d",&t); 60 while(t--){ 61 memset(a,0,sizeof(a)); 62 int n; 63 scanf("%d",&n); 64 int m=n*n; 65 for(int i=0;i<m;i++){ 66 char c=getchar(); 67 while(c!='y'&&c!='w') c=getchar(); 68 a[i][m]=c=='w'?1:0; 69 } 70 init(n); 71 int ans=gauss(m,m); 72 if(ans==-1) puts("inf"); 73 else printf("%d ",ans); 74 } 75 }
SETI
题意:
模线性方程组高斯消元模板
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=75; 7 int a[maxn][maxn]; 8 int x[maxn]; 9 char s[75]; 10 int mod; 11 12 int gcd(int a,int b){ 13 return b==0?a:gcd(b,a%b); 14 } 15 int lcm(int a,int b){ 16 return a/gcd(a,b)*b; 17 } 18 void exgcd(int a,int b,int &d,int &x,int &y){ 19 if(!b){d=a;x=1;y=0;} 20 else {exgcd(b,a%b,d,y,x); y-=x*(a/b);} 21 } 22 23 int gauss(int n,int m){ 24 int r,c; 25 for(r=0,c=0;r<n&&c<m;c++){ 26 int max_r=r; 27 for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i; 28 if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]); 29 if(!a[r][c]) continue; 30 for(int i=r+1;i<n;i++) if(a[i][c]){ 31 int d=lcm(abs(a[i][c]),abs(a[r][c])); 32 int t1=d/a[i][c],t2=d/a[r][c]; 33 for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod; 34 } 35 r++; 36 } 37 for(int i=r;i<n;i++) if(a[i][m]) return -1; //无解 38 for(int i=r-1;i>=0;i--){ 39 x[i]=a[i][m]; 40 for(int j=i+1;j<m;j++){ 41 x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod; 42 } 43 int x1,y1,d; 44 exgcd(a[i][i],mod,d,x1,y1); 45 x1=((x1%mod)+mod)%mod; 46 x[i]=x[i]*x1%mod; 47 } 48 if(r<m) return m-r; //自由变元 49 return 1;//唯一解 50 } 51 int quickpow(int a,int b,int mod){ 52 int ans=1,temp=a%mod; 53 while(b){ 54 if(b&1) ans=(ans*temp)%mod; 55 b>>=1; 56 temp=temp*temp%mod; 57 } 58 return ans; 59 } 60 int main(){ 61 int t; 62 scanf("%d",&t); 63 while(t--){ 64 int n,m; 65 memset(a,0,sizeof(a)); 66 memset(x,0,sizeof(x)); 67 scanf("%d%s",&mod,s); 68 n=m=strlen(s); 69 for(int i=0;i<n;i++){ 70 a[i][m]=s[i]=='*'?0:s[i]-'a'+1; 71 for(int j=0;j<n;j++) 72 a[i][j]=quickpow(i+1,j,mod); 73 } 74 int ans=gauss(n,m); 75 for(int i=0;i<n-1;i++) printf("%d ",x[i]); 76 printf("%d ",x[n-1]); 77 } 78 return 0; 79 }
Kind of a Blur
题意:让求矩阵x。给出n×m的矩阵b,b[i][j]为到这个位置的曼哈顿距离不大于d的x[i][j]的和除以个数。
浮点数高斯消元模板题。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const double eps=1e-12; 4 const int maxn=22; 5 int n,m; 6 int tot; 7 int d; 8 double a[maxn*maxn][maxn*maxn]; 9 double b[maxn][maxn]; 10 double x[maxn*maxn]; 11 12 int count_(int x,int y){ 13 int ans=0; 14 for(int i=0;i<n;i++) 15 for(int j=0;j<m;j++) 16 if(abs(i-x)+abs(y-j)<=d) ans++; 17 return ans; 18 } 19 20 void init(){ 21 int num=0; 22 for(int i=0;i<n;i++){ 23 for(int j=0;j<m;j++){ 24 int cnt=count_(i,j); 25 for(int k=0;k<n;k++) 26 for(int g=0;g<m;g++){ 27 if(abs(k-i)+abs(g-j)<=d) 28 a[num][k*m+g]=1.0/cnt; 29 } 30 a[num++][tot]=b[i][j]; 31 } 32 } 33 } 34 void gauss(){ 35 for(int r=0;r<tot;r++){ 36 int max_r=r; 37 for(int i=r+1;i<tot;i++) 38 if(fabs(a[i][r])>fabs(a[max_r][r])) max_r=i; 39 if(max_r!=r){ 40 for(int j=0;j<=tot;j++) swap(a[r][j],a[max_r][j]); 41 } 42 if(fabs(a[r][r])<eps) continue; 43 //消元 44 for(int i=r+1;i<tot;i++){ 45 double ta=a[i][r]/a[r][r]; 46 for(int j=r;j<=tot;j++) a[i][j]-=ta*a[r][j]; 47 } 48 /* 49 精度更高 50 for(int j=tot;j>=r;j--){ 51 for(int i=r+1;i<tot;i++) a[i][j]-=a[i][r]/a[r][r]*a[r][j]; 52 } 53 */ 54 } 55 //回代 56 for(int i=tot-1;i>=0;i--){ 57 double temp=a[i][tot]; 58 for(int j=i+1;j<tot;j++) 59 temp-=a[i][j]*x[j]; 60 x[i]=temp/a[i][i]; 61 } 62 } 63 int main(){ 64 int kase=0; 65 while(scanf("%d%d%d",&m,&n,&d)!=EOF&&(n+m+d)){ 66 memset(a,0,sizeof(a)); 67 tot=n*m; 68 if(kase++) puts(""); 69 for(int i=0;i<n;i++) 70 for(int j=0;j<m;j++) 71 scanf("%lf",&b[i][j]); 72 init(); 73 gauss(); 74 int id=0; 75 for(int i=0;i<n;i++){ 76 for(int j=0;j<m;j++) printf("%8.2lf",x[id++]); 77 puts(""); 78 } 79 } 80 return 0; 81 }
The Water Bowls
题意:还是开关问题~每个开关可以影响自己和相邻的灯。
枚举自由变元
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 const int inf=0x3f3f3f3f; 7 //const int mod=2; 8 const int maxn=25; 9 int a[maxn][maxn]; 10 int x[maxn],free_x[maxn]; 11 int n,m; 12 /* 13 int gcd(int a,int b){ 14 return b==0?a:gcd(b,a%b); 15 } 16 int lcm(int a,int b){ 17 return a/gcd(a,b)*b; 18 } 19 void exgcd(int a,int b,int &d,int &x,int &y){ 20 if(!b){d=a;x=1;y=0;} 21 else {exgcd(b,a%b,d,y,x); y-=x*(a/b);} 22 } 23 */ 24 25 int gauss(int n,int m){ 26 int r,c; 27 int num=0; 28 for(r=0,c=0;r<n&&c<m;c++){ 29 int max_r=r; 30 for(int i=r+1;i<n;i++) if(abs(a[i][c]) > abs(a[max_r][c])) max_r=i; 31 if(max_r!=r) for(int j=c;j<=m;j++) swap(a[r][j],a[max_r][j]); 32 if(!a[r][c]) {free_x[num++]=c;continue;} // 33 for(int i=r+1;i<n;i++) if(a[i][c]){ 34 /* 35 int d=lcm(abs(a[i][c]),abs(a[r][c])); 36 int t1=d/a[i][c],t2=d/a[r][c]; 37 for(int j=c;j<=m;j++) a[i][j]=((a[i][j]*t1-a[r][j]*t2)%mod+mod)%mod; 38 */ 39 for(int j=c;j<=m;j++) a[i][j]^=a[r][j]; 40 } 41 r++; 42 } 43 for(int i=r;i<n;i++) if(a[i][m]) return -1; 44 /* 45 for(int i=r-1;i>=0;i--){ 46 x[i]=a[i][m]; 47 for(int j=i+1;j<m;j++){ 48 x[i]=((x[i]-a[i][j]*x[j])%mod+mod)%mod; 49 } 50 int x1,y1,d; 51 exgcd(a[i][i],mod,d,x1,y1); 52 x1=((x1%mod)+mod)%mod; 53 x[i]=x[i]*x1%mod; 54 } 55 */ 56 int sta=1<<(m-r); 57 int res=inf; 58 //枚举自由变元 59 for(int i=0;i<sta;i++){ 60 int cnt=0; 61 int id=i; 62 for(int j=0;j<m-r;j++){ 63 x[free_x[j]]=(id&1); 64 if(x[free_x[j]]) cnt++; 65 id>>=1; 66 } 67 for(int j=r-1;j>=0;j--){ 68 int temp=a[j][m]; 69 for(int k=j+i;k<m;k++){ 70 if(a[j][k]) temp^=x[k]; 71 } 72 x[j]=temp; 73 if(x[j]) cnt++; 74 } 75 if(cnt<res) res=cnt; 76 } 77 return res; 78 } 79 void init(int n,int m){ 80 for(int i=0;i<n;i++){ 81 for(int j=0;j<m;j++) a[i][j]=0; 82 a[i][i]=1; 83 if(i>0) a[i][i-1]=1; 84 if(i<19) a[i][i+1]=1; 85 } 86 } 87 int main(){ 88 init(20,20); 89 memset(free_x,0,sizeof(free_x)); 90 for(int i=0;i<20;i++){ 91 scanf("%d",&a[i][20]); 92 } 93 int ans=gauss(20,20); 94 printf("%d ",ans); 95 return 0; 96 }