• HDU_5833_高斯消元


    参考自:http://www.cnblogs.com/flipped/p/5771492.html

    自己做的时候不知道如何求种数。看了题解,感觉思路灰常巧妙。同时也感觉这是一道好题。

    精髓在于转化为线性方程组。

    求素数的思想,和高斯消元需要多加熟悉。

    300个最大质因数小于2000的数,选若干个它们的乘积为完全平方数有多少种方案。

    合法方案的每个数的质因数的个数的奇偶值异或起来为0。

    比如12=2^2*3,对应的奇偶值为01(2的个数是偶数为0,3的个数是奇数为1),3的对应奇偶值为01,于是12*3是完全平方数。

    然后异或方程组就是:

    a11x1+a12x2+...+a1nxn=0

    a21x1+a22x2+...+a2nxn=0

    ...

    an1x1+an2x2+...+annxn=0

    aij:第i个质数(2000内有303个质数)在第j个数里是奇数个则为1,否则为0。

    xi:第i个数(最多300个数)被选则为1,否则为0。

    求出有多少种解即可。(异或方程组高斯消元求秩,然后解就有2^(n-rank)种,减去全为0的解)

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    #define LL long long
    #define mod 1000000007
    
    const int N=2000;
    const int M=310;
    
    int prime[N+2],cnt;
    int n,t,mat[M][M];
    LL a[M];
    
    void getPrime()   //求2000以内的所有质数
    {
        for(int i=2; i<=N; i++)
        {
            if(!prime[i])
                prime[++cnt]=i;
            for(int j=1; j<=cnt&&prime[j]<=N/i; j++)
            {
                prime[prime[j]*i]=1;
                if(i%prime[j]==0)
                    break;
            }
        }
    }
    
    int Rank(int c[][M])   //高斯消元求方程组的秩(线性表换将矩阵转化为上阶梯形矩阵)
    {
        int i=0,j=0,k,r,u;
        while(i<=cnt&&j<=n)
        {
            r=i;
            while(c[r][j]==0&&r<=cnt) r++;
            if(c[r][j])
            {
                swap(c[i],c[r]);
                for(u=i+1; u<=cnt; u++)
                    if(c[u][j])
                        for(k=i; k<=n; k++)
                            c[u][k]^=c[i][k];
                i++;
            }
            j++;
        }
        return i;
    }
    
    int solve()
    {
        memset(mat,0,sizeof(mat));
        for(int i=1; i<=n; i++)
            for(int j=1; j<=cnt; j++)
            {
                LL tmp=a[i];
                while(tmp%prime[j]==0)
                {
                    tmp/=prime[j];
                    mat[j][i]^=1;
                }
            }
        int b=n-Rank(mat);
        LL ans=1,k=2;
        while(b)       //快速幂
        {
            if(b&1)
                ans=ans*k%mod;
            k=k*k%mod;
            b>>=1;
        }
        return ans-1;
    }
    
    int main()
    {
        int cas=1;
        getPrime();
    
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%I64d",&a[i]);//cout<<"*";
            printf("Case #%d:
    %d
    ",cas++,solve());
        }
    }
  • 相关阅读:
    MyBatis 知识点梳理
    SSH无密码登录的原理及配置
    Maven学习笔记
    阿里Java开发电话面试经历惨败
    Java生成验证码(二)
    Java生成验证码(一)
    Hibernate 知识点梳理
    数据结构线性表顺序表示 (二)
    replace tabs with the proper number of blanks
    数据结构线性表顺序表示 (三)
  • 原文地址:https://www.cnblogs.com/jasonlixuetao/p/5773662.html
Copyright © 2020-2023  润新知