UVa 11542 (高斯消元 异或方程组) Square

书上分析的太清楚,我都懒得写题解了。=_=||

 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\n", (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\n", (1LL << (n-r)) - 1);
68     }
69 
70     return 0;
71 }
代码君

 

posted @ 2015-03-14 21:16  AOQNRMGYXLMV  阅读(286)  评论(0编辑  收藏  举报