• 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 }
  • 相关阅读:
    基于Visual C++2013拆解世界五百强面试题--题13-找最大公共子字符串
    基于Visual C++2013拆解世界五百强面试题--题12-进制转换
    Color颜色对照表
    根据选择打开相应的程序
    复制一个5G文件只需要两秒,全网最牛方法!
    判断一个男人穷还是富,只看这几点!
    判断一个男人穷还是富,只看这几点!
    判断一个男人穷还是富,只看这几点!
    16年国庆假期期间兼职所悟
    16年国庆假期期间兼职所悟
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4238947.html
Copyright © 2020-2023  润新知