题目大意:
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 }