zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    【linux]】lighttpd的日志格式
    【vi】awk为指定行的指定字段添加一个单词
    【Android】命令行操作-启动应用程序
    CCS设置第一个li的元素与其他li样式不同
    nginx+tomcat 下POST响应参数过大无法显示完整及文件下载服务遇到过大文件无法下载解决办法
    有重复行,查询时只保留最新一行的sql
    Android定时执行和停止某任务
    MySQL每天自动增加分区
    <html:option获取文本值
    easyui datagrid 增删改查示例
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4238947.html
Copyright © 2011-2022 走看看