嘛,这个东西比较妙。。。为什么这么说呢。。。
这个题过程有点难懂。。。。不过还行。。。。
嘛,就是在高斯消元时候,把原矩阵的增广矩阵进行同步消元。。
但由于方程数量不足,所以增广矩阵不唯一
于是,要枚举增广矩阵的每个解的情况,然后判断合法与否
然后这个题就可以解决了
具体在下面。。。(欸,讲道理,硬要写,要把矩阵全部介绍一次。。。。,其实也没什么好写的)
差不多要讲的就是增广矩阵不单单是个值,一些表达式什么的也可以进去。。。当然还有函数这些东西。。。。。。(多项式矩阵)
进行高斯消元是在整数域上,所以要用lcm来搞,直接实数域的做法会wa。。。。
并且 注意 矩阵变换 是一个整体。。。。。(千万不要像我一样,傻傻的拿增广矩阵的lcm来玩。。。)
#include<bits/stdc++.h>
using namespace std;
int n;
char tu[4][28];
int a[28][28] , b[28][28];
int now[28];
int gcd(int x , int y){
if(y == 0)return x;
return gcd(y , x % y);
}
void init(){
memset(a , 0 , sizeof(a));
cin>>n;
for(int i = 1 ; i <= 3 ; i++){
for(int j = 1 ; j <= n ; j++){
cin>>tu[i][j];
}
}
for(int i = n ; i >= 1 ; i--){
a[i][tu[1][n - i + 1] - 'A' + 1]++;
a[i][tu[2][n - i + 1] - 'A' + 1]++;
a[i][tu[3][n - i + 1] - 'A' + 1]--;
b[i][i] = n;
if(i != 1)b[i][i - 1] = (-1);
}
}
int guess(){
for(int i = 1 ; i <= n ; i++){
int jl = i;
while(a[jl][i] == 0 && jl <= n)jl++;
if(jl > n)return 2;
for(int j = 1 ; j <= n + 1 ; j++)swap(a[jl][j] , a[i][j]) , swap(b[jl][j] , b[i][j]);
for(int j = 1 ; j <= n ; j++){
if(i == j || a[j][i] == 0)continue;
int lcm = (a[j][i] / gcd(a[j][i] , a[i][i])) * a[i][i];
int zz = a[j][i];
for(int k = 1 ; k <= n + 1 ; k++){
b[j][k] = b[j][k] * (lcm / zz) - b[i][k] * (lcm / a[i][i]);
a[j][k] = a[j][k] * (lcm / zz) - a[i][k] * (lcm / a[i][i]);
}
}
}
}
int js[35],sz[35];
/*
把d带进去。然后一行一行判断合不合法,不合法立刻返回
*/
int check(){
memset(js , -1 , sizeof(js));
for(int i = 1 ; i <= n ; i++){
int sum = 0;
for(int j = 1 ; j <= n ; j++)sum = sum + b[i][j] * now[j];
sz[i] = sum / a[i][i];
if(sz[i] < 0 || sz[i] >=n )return 2;
if(js[sz[i]] != (-1))return 2;
js[sz[i]] = 1;
}
}
int main(){
init();
guess();
for(long long s = 0 ; s < (1 << n) ; s++){
for(int i = 0 ; i < n ; i++){
if(s & (1<<i))now[i] = 1;
else now[i] = 0;
}
if(check() == 2)continue;
break;
}
for(int i = 1; i <= n ; i++)cout<<sz[i]<<" ";
}