POJ 2065 高斯消元求解问题

题目大意:

f[k] = ∑a[i]*k^i % p

每一个f[k]的值就是字符串上第 k 个元素映射的值,*代表f[k] = 0 , 字母代表f[k] = str[i]-'a'+1

把每一个k^i求出保存在矩阵中,根据字符串的长度len,那么就可以得到len行的矩阵,利用高斯消元解决这个线性方程组

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 using namespace std;
  5 
  6 const int N = 105;
  7 //a[i][j]表示线性方程组形成的矩阵上的第i行第j个元素
  8 //x[]保存线性方程组的解集
  9 int a[N][N] , p , x[N];
 10 char str[N];
 11 
 12 //求取模的幂运算 x^y % mod
 13 int pow(int x , int y , int mod)
 14 {
 15     int ans = 1;
 16     while(y){
 17         if(y & 1){
 18             ans *= x;
 19             ans %= mod;
 20         }
 21         x *= x;
 22         x %= mod;
 23         y>>=1;
 24     }
 25     return ans;
 26 }
 27 
 28 int gcd(int a , int b)
 29 {
 30     if(b == 0) return a;
 31     else return gcd(b , a%b);
 32 }
 33 
 34 int lcm(int a , int b)
 35 {
 36     return a/gcd(a , b)*b;//先除后乘防止溢出
 37 }
 38 
 39 inline int my_abs(int x)
 40 {
 41     return x>=0?x:-x;
 42 }
 43 
 44 inline void my_swap(int &a , int &b)
 45 {
 46     int tmp = a;
 47     a = b , b = tmp;
 48 }
 49 /*
 50 高斯消元解线性方程组的解
 51 有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var
 52 总是考虑上三角部分,所以内部更新总是只更新了上三角部分
 53 */
 54 int gauss(int equ , int var , int mod)
 55 {
 56     int max_r; // 当前这列绝对值最大的行
 57     int col; // 当前处理的列
 58     int ta , tb;
 59     int Lcm , tmp;
 60 
 61     for(int i=0 ; i<var ; i++)
 62         x[i] = 0;
 63 
 64     //转化为阶梯形矩阵
 65     col = 0;//一开始处理到第0列
 66     for(int k=0 ; k<equ ; k++,col++){
 67     /*
 68     枚举当前处理的行
 69     找到该行col列元素绝对值最大的那行与第k行交换,
 70     这样进行除法运算的时候就可以避免小数除以大数了
 71     */
 72         max_r = k;
 73         for(int i = k+1 ; i<equ ; i++)
 74             if(my_abs(a[i][col]) > my_abs(a[max_r][col]))
 75                 max_r = i;
 76         if(max_r != k){
 77             //交换两行的数据
 78             for(int i=k ; i<var+1 ; i++)
 79                 my_swap(a[max_r][i] , a[k][i]);
 80         }
 81 
 82         if(a[k][col] == 0){
 83             //说明该col列第k行以下全是0了,则处理当前行的下一列
 84             k--;
 85             continue;
 86         }
 87 
 88         for(int i=k+1 ; i<equ ; i++){
 89             //枚举要删去的行
 90             if(a[i][col] != 0 ){
 91                 Lcm = lcm(my_abs(a[i][col]) , my_abs(a[k][col]));
 92                 ta = Lcm / my_abs(a[i][col]);
 93                 tb = Lcm / my_abs(a[k][col]);
 94                 if(a[i][col] * a[k][col] < 0) tb = -tb;//异号相加
 95                 for(int j = col ; j<var+1 ; j++)
 96                     a[i][j] = ((a[i][j]*ta)%mod - (a[k][j]*tb)%mod + mod) % mod;
 97             }
 98         }
 99     }
100     //唯一解的情况:在var*(var+1) 的增广矩阵中形成严格的上三角阵
101     //计算x[n-1] , x[n-2] .... x[0] 回代计算,先得到后面的值,推到前面的值
102     for(int i=var-1 ; i>=0 ; i--){
103         tmp = a[i][var];
104         for(int j=i+1 ; j<var ; j++){
105             if(a[i][j] != 0 ) tmp -= a[i][j]*x[j];
106             tmp = (tmp%mod+mod)%mod;
107         }
108         while(tmp%a[i][i])
109             tmp+=mod;
110         x[i] = (tmp / a[i][i])%mod;
111     }
112     return 0;
113 }
114 
115 int main()
116 {
117    // freopen("a.in" , "r" , stdin);
118     int T;
119     scanf("%d" , &T);
120     while(T--)
121     {
122         scanf("%d%s" , &p , str);
123         int len = strlen(str);
124         //填写矩阵中的元素
125         for(int i=0 ; i<len ; i++){
126             if(str[i] == '*') a[i][len] = 0;
127             else a[i][len] = (int)(str[i] - 'a' + 1);
128             for(int j=0 ; j<len ; j++)
129                 a[i][j] = pow(i+1 , j , p);
130         }
131         gauss(len , len , p);
132         for(int i=0 ; i<len ; i++){
133             if(i == 0) printf("%d" , x[i]);
134             else printf(" %d" , x[i]);
135         }
136         puts("");
137     }
138     return 0;
139 }
原文地址:https://www.cnblogs.com/CSU3901130321/p/4238947.html