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 }

 

你可能感兴趣的:(poj)