• 2013多校第四场 E题 ZZ的研究


    题意:

      有N(n<=1000)个数 a1,a2,..,an,  ai <= 10^15, 取其中部分组合相乘的到数是一个完全平方数.求方案总数.

    其中保证 ai 不包含大于500的质因子.

    解题思路:

      解决本题需要有,线性代数基础.  涉及到关于矩阵的初等变换与高斯消元.求解齐次方程.

      首先考虑,一个数 x = p1^e1 * p2^e2 * ... * pn^en

      若其是一个完全平方数,则  所有的 ei % 2 == 0 .

      另外. 取部分数相乘. 例如三个数 ai*aj*ak = x ,此时我们只关心的是其

    对应的质因子的幂皆为偶数. 所以对于 ai  =  p1^e1 * p2^e2 * ... * pk*ek 而言.

    我们只需要知道对应的  ( e1, e2, e3, ... , ek )的奇偶性就可以了.

      假定其 ei = 0, 则其为 偶数,  ei = 0, 则其为 奇数. 

      则对于每一个数字, 我们都可以用一个 01向量表示, 因为题目已说明,不同质因子不会超过500. 

    通过素数筛选500以内质数,发现其不超过88个.设其为m个, 所以我们得出, 对于每一个数 ai ,我们都可以用一个 88维的01列向量表示.

      而对于 n 个数.  则有 n个 列向量来表示

      | a11, a12, ...,a1n  |

      | a21, a22, ...,a2n  |

      | ...         |

      | am1,am2,...,amn |

      假设其为 A,   则有一个n维列向量向量 x (x1,x2,..,xn),其中 xi 表示第i个数取还是不取,所以 xi = 0 or 1.

    更直观的反映是, 若 xi = 0,  则代表着第i个数不取, 意味着第对于矩阵A而言, 第j列的值与 N维列向量计算厚皆为0.

      使其得到 一个 m维列向量 b( b1,b2,...,bm ),形式如下

        A*x = b .

      其中 b ( b1,b2, ..., bm ) 即代表着 组合的数, res = p1^e1 * p2^e2 * ... * pm*em, 其 (e1, e2, .., em) 是否对应

    位置是否为偶数,   例如 bi = 0, 则 ei 为偶数, bi = 1, ei 为奇数. 

      若要保证 res 是一个完全平方数,  则 b( b1, b2, ..., bm ) 必须为 b(0,0,...,0) 所以得到了一个齐次方程组.

      通过高斯消元.得出此矩阵的秩 r, 则此时秩的含义是, 有r个未知量xi能够确定.

      此时还有 n-r个未知量是不确定.  而 xi 的取值只有 0 or 1.  则此时解的方案数为  2^(n-r) ,

      另外, 当 n-r个未知量都为空时, 不满足题目要求. 所以需要减去1, 去掉空集的情况. 

    View Code
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 1010;
    typedef int Matrix[N][N];
    typedef long long LL;
    int pre[N],vis[N];
    int getprime(int x){
        memset(vis,0,sizeof(vis));
        vis[1] = 1; 
        int cnt = 0;
        for(int i = 2; i <= x; i++){
            if( vis[i] == 0 ) pre[cnt++] = i;
            for(int j = 0; j < cnt && i*pre[j] <= x; j++){
                vis[ i*pre[j] ] = 1;
                if( i%pre[j] == 0 ) break;
            } 
        }
        return cnt;
    }
    //m个方程n个变量
    int rank(Matrix A, int m, int n)
    {
        int i = 0, j = 0;
        while( i < m && j < n ){
            int r = i; //目前处理第i行,j列,寻找j列不为0的行r
            for(int k = i; k < m; k++)
                if( A[k][j] ){ r = k; break; }
            if( A[r][j] ){//若找到
                if( r != i ) //若不是i,则初等变换,交换(i,r)行
                    for(int k = 0; k < n; k++) swap( A[i][k] , A[r][k] );
                for(int u = i+1; u < m; u++){
                    if( A[u][j] )
                        for(int k = j; k < n; k++)
                            A[u][k] ^= A[i][j];
                }    
                i++; //处理下一行    
            }
            j++; //处理下一列
        }
        return i;
    }
    int main(){
        int T, cnt = getprime(500);
        scanf("%d", &T);
        while( T-- ){
            int n, m = 0; scanf("%d", &n);
            LL x;
            Matrix A; memset(A,0,sizeof(A));    
            for(int i = 0; i < n; i++){
                scanf("%lld", &x );
                for(int j = 0; j < cnt && x >= pre[j]; j++){
                    while( x%pre[j] == 0 ){
                        m = max( m, j );
                        A[j][i] ^= 1;
                        x /= pre[j];    
                    }    
                } 
            }    
            int r = rank( A, m+1, n );
            printf("%lld\n", (1LL<<(n-r)) - 1 );
        }
        return 0;
    }
  • 相关阅读:
    2、selinux服务的操作
    1、添加nginx到全局变量中
    linux每日命令(1):which
    QT重载基类绘制函数并在基类绘制结果基础上进行子类的绘制
    QT信号槽无法正常通信的原因
    mapgis6.7+加密狗+二次开发SDK库
    KMP算法参考及C语言实现
    elastic search
    RabbitMq docker集群
    RabbitMq安装
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3049633.html
Copyright © 2020-2023  润新知