书上分析的太清楚,我都懒得写题解了。=_=||
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxp = 100; 8 const int maxn = 500; 9 bool vis[maxn + 10]; 10 int prime[maxp], pcnt = 0; 11 12 void Init() 13 { 14 int m = sqrt(maxn + 0.5); 15 for(int i = 2; i <= m; i++) if(!vis[i]) 16 for(int j = i*i; j <= maxn; j += i) vis[j] = true; 17 for(int i = 2; i <= maxn; i++) if(!vis[i]) prime[pcnt++] = i; 18 } 19 20 typedef int Matrix[maxn][maxn]; 21 22 Matrix A; 23 24 int rank(Matrix A, int m, int n) 25 {//求系数矩阵A的秩,m个方程,n个未知数 26 int i = 0, j = 0; 27 while(i < m && j < n) 28 { 29 int r = i, k; 30 for(k = r; k < m; k++) if(A[k][j]) { r = k; break; } 31 if(k < m) 32 { 33 if(r != i) for(int k = 0; k < n; k++) swap(A[r][k], A[i][k]); 34 for(int k = i+1; k < m; k++) if(A[k][j]) 35 for(int l = j; l < n; l++) A[k][l] ^= A[i][l]; 36 i++; 37 } 38 j++; 39 } 40 return i; 41 } 42 43 int main() 44 { 45 //freopen("in.txt", "r", stdin); 46 47 Init(); 48 int T; 49 scanf("%d", &T); 50 while(T--) 51 { 52 memset(A, 0, sizeof(A)); 53 int n, M = 0; 54 scanf("%d", &n); 55 for(int i = 0; i < n; i++) 56 { 57 long long x; 58 scanf("%lld", &x); 59 for(int j = 0; j < pcnt; j++) while(x % prime[j] == 0) 60 { 61 M = max(M, j); 62 x /= prime[j]; 63 A[j][i] ^= 1; 64 } 65 } 66 int r = rank(A, M+1, n);//共用到前M+1个素数 67 printf("%lld ", (1LL << (n-r)) - 1); 68 } 69 70 return 0; 71 }
最后lrj老师提到了还可以用状压加速消元,因为500以内的素数不超过100个,所以我用了两个64位的long long来表示一个方程。第一份代码16ms,状压以后12ms,快了四分之一。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxp = 100; 8 const int maxn = 500; 9 bool vis[maxn + 10]; 10 int prime[maxp], pcnt = 0; 11 12 void Init() 13 { 14 int m = sqrt(maxn + 0.5); 15 for(int i = 2; i <= m; i++) if(!vis[i]) 16 for(int j = i*i; j <= maxn; j += i) vis[j] = true; 17 for(int i = 2; i <= maxn; i++) if(!vis[i]) prime[pcnt++] = i; 18 } 19 20 typedef long long Matrix[maxn][2]; 21 22 Matrix A; 23 24 int rank(Matrix A, int m, int n) 25 {//求系数矩阵A的秩,m个方程,n个未知数 26 int i = 0, j = 0, len = n / 64; 27 while(i < m && j < n) 28 { 29 int r = i, k; 30 for(k = r; k < m; k++) if(A[k][j/64] & (1LL<<(j%64))) { r = k; break; } 31 if(k < m) 32 { 33 if(r != i) for(int k = 0; k <= len; k++) swap(A[r][k], A[i][k]); 34 for(int k = i+1; k < m; k++) if(A[k][j/64] & (1LL<<(j%64))) 35 for(int l = 0; l <= len; l++) A[k][l] ^= A[i][l]; 36 i++; 37 } 38 j++; 39 } 40 return i; 41 } 42 43 int main() 44 { 45 //freopen("in.txt", "r", stdin); 46 47 Init(); 48 int T; 49 scanf("%d", &T); 50 while(T--) 51 { 52 memset(A, 0, sizeof(A)); 53 int n, M = 0; 54 scanf("%d", &n); 55 for(int i = 0; i < n; i++) 56 { 57 long long x; 58 scanf("%lld", &x); 59 for(int j = 0; j < pcnt; j++) while(x % prime[j] == 0) 60 { 61 M = max(M, j); 62 x /= prime[j]; 63 A[j][i/64] ^= (1LL << (i%64) ); 64 } 65 } 66 int r = rank(A, M+1, n);//共用到前M+1个素数 67 printf("%lld ", (1LL << (n-r)) - 1); 68 } 69 70 return 0; 71 }