题目连接:http://poj.org/problem?id=2065
高斯消元求出上三角矩阵后,求出 a×x = b(mod p),即 a×x - p×y=b,用扩展欧几里得求出x。
1 //STATUS:C++_AC_32MS_156KB 2 #include <functional> 3 #include <algorithm> 4 #include <iostream> 5 //#include <ext/rope> 6 #include <fstream> 7 #include <sstream> 8 #include <iomanip> 9 #include <numeric> 10 #include <cstring> 11 #include <cassert> 12 #include <cstdio> 13 #include <string> 14 #include <vector> 15 #include <bitset> 16 #include <queue> 17 #include <stack> 18 #include <cmath> 19 #include <ctime> 20 #include <list> 21 #include <set> 22 #include <map> 23 using namespace std; 24 //using namespace __gnu_cxx; 25 //define 26 #define pii pair<int,int> 27 #define mem(a,b) memset(a,b,sizeof(a)) 28 #define lson l,mid,rt<<1 29 #define rson mid+1,r,rt<<1|1 30 #define PI acos(-1.0) 31 //typedef 32 typedef long long LL; 33 typedef unsigned long long ULL; 34 //const 35 const int N=73; 36 const int INF=0x3f3f3f3f; 37 const int MOD=100000,STA=8000010; 38 const LL LNF=1LL<<60; 39 const double EPS=1e-8; 40 const double OO=1e15; 41 const int dx[4]={-1,0,1,0}; 42 const int dy[4]={0,1,0,-1}; 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 44 //Daily Use ... 45 inline int sign(double x){return (x>EPS)-(x<-EPS);} 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;} 49 template<class T> inline T Min(T a,T b){return a<b?a:b;} 50 template<class T> inline T Max(T a,T b){return a>b?a:b;} 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} 55 //End 56 57 int A[N][N];//增广矩阵 58 int B[N];//解集 59 bool free_x[N];//标记是否是不确定的变元 60 int T,n,m,k,p; 61 62 // 63 void Debug(int equ,int var) 64 { 65 int i, j; 66 for(i=0;i<equ;i++){ 67 for(j=0;j<=var;j++) 68 printf("%4d",A[i][j]); 69 putchar('\n'); 70 } 71 putchar('\n'); 72 } 73 // 74 75 void extgcd(int a,int b,int &d,int &x,int &y) 76 { 77 if(!b){d=a;x=1;y=0;} 78 else {extgcd(b,a%b,d,y,x);y-=x*(a/b);} 79 } 80 81 inline int gcd(int a,int b) 82 { 83 int t; 84 while(b!=0) 85 { 86 t=b; 87 b=a%b; 88 a=t; 89 } 90 return a; 91 } 92 93 inline int lcm(int a,int b) 94 { 95 return a/gcd(a,b)*b;//先除后乘防溢出 96 } 97 98 // 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解, 99 //-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数) 100 //有equ个方程,var个变元。增广矩阵行数为equ,分别为0到equ-1,列数为var+1,分别为0到var. 101 int Gauss(int equ,int var) 102 { 103 int i,j,k; 104 int max_r; // 当前这列绝对值最大的行. 105 int col; //当前处理的列 106 int ta,tb; 107 int LCM; 108 int temp; 109 int free_x_num; 110 int free_index; 111 112 for(int i=0;i<=var;i++) 113 { 114 B[i]=0; 115 free_x[i]=true; 116 } 117 //转换为阶梯阵. 118 col=0; // 当前处理的列 119 for(k = 0;k < equ && col < var;k++,col++) 120 {// 枚举当前处理的行. 121 // 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差) 122 max_r=k; 123 for(i=k+1;i<equ;i++) 124 { 125 if(abs(A[i][col])>abs(A[max_r][col])) max_r=i; 126 } 127 if(max_r!=k) 128 {// 与第k行交换. 129 for(j=k;j<var+1;j++) swap(A[k][j],A[max_r][j]); 130 } 131 if(A[k][col]==0) 132 {// 说明该col列第k行以下全是0了,则处理当前行的下一列. 133 k--; 134 continue; 135 } 136 for(i=k+1;i<equ;i++) // i=0高斯约当消元,才能在多解的情况下判断变元是否确定 137 {// 枚举要删去的行. 138 if(A[i][col]!=0 && i!=k) 139 { 140 LCM = lcm(abs(A[i][col]),abs(A[k][col])); 141 ta = LCM/abs(A[i][col]); 142 tb = LCM/abs(A[k][col]); 143 if(A[i][col]*A[k][col]<0)tb=-tb;//异号的情况是相加 144 for(j=0;j<=var;j++) 145 { 146 A[i][j] = (A[i][j]*ta - A[k][j]*tb)%p; 147 } 148 } 149 } 150 } 151 152 // Debug(equ,var); 153 154 // 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0). 155 /* 156 for (i = k; i < equ; i++) 157 { 158 if (A[i][col] != 0) return -1; 159 } 160 // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换. 161 // 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵. 162 // 且出现的行数即为自由变元的个数. 163 if (k < var)return 1; 164 { 165 // 首先,自由变元有var - k个,即不确定的变元至少有var - k个. 166 for (i = k - 1; i >= 0; i--) 167 { 168 // 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行. 169 // 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的. 170 free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元. 171 for (j = 0; j < var; j++) 172 { 173 if (A[i][j] != 0 && free_x[j]) free_x_num++, free_index = j; 174 } 175 if (free_x_num > 1) continue; // 无法求解出确定的变元. 176 // 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的. 177 temp = A[i][var]; 178 for (j = 0; j < var; j++) 179 { 180 if (A[i][j] != 0 && j != free_index) temp -= A[i][j] * x[j]; 181 } 182 x[free_index] = temp / A[i][free_index]; // 求出该变元. 183 free_x[free_index] = 0; // 该变元是确定的. 184 } 185 return var - k; // 自由变元有var - k个. 186 }*/ 187 // 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵. 188 // 计算出Xn-1, Xn-2 ... X0. 189 for (i = var - 1; i >= 0; i--) 190 { 191 temp = A[i][var]; 192 for (j = i + 1; j < var; j++) 193 { 194 if (A[i][j] != 0) temp = (temp-(A[i][j] * B[j]))%p; 195 } 196 // if (temp % A[i][i] != 0) return -2; // 说明有浮点数解,但无整数解. 197 int x,y,d; 198 extgcd(A[i][i],p,d,x,y); 199 B[i]=((x*(temp/d))%p+p)%p; 200 // x[i] = (temp / A[i][i])%p; 201 } 202 return 0; 203 } 204 205 int main() 206 { 207 // freopen("in.txt","r",stdin); 208 int i,j,t; 209 char s[N]; 210 scanf("%d",&T); 211 while(T--) 212 { 213 scanf("%d%s",&p,s); 214 n=strlen(s); 215 for(i=0;i<n;i++){ 216 t=1; 217 for(j=0;j<n;j++){ 218 A[i][j]=t; 219 t=(t*(i+1))%p; 220 } 221 A[i][j]=s[i]=='*'?0:s[i]-'a'+1; 222 } 223 224 Gauss(n,n); 225 // Debug(n,n); 226 227 printf("%d",B[0]); 228 for(i=1;i<n;i++) 229 printf(" %d",B[i]); 230 putchar('\n'); 231 } 232 return 0; 233 }