zoukankan      html  css  js  c++  java
  • UVa11542

    题目链接

    分析:
    题目特意说到,不含有超过500的素因子
    这就是在提示我们可以质因数分解
    我们把这n个数分解成若干素数乘积的形式,并用一个向量表示

    如:4 6 10 15
    这n=4个数中,涉及到的素数只有2,3,5这三个
    分解后:
    4=2^2*3^0*5^0 ——>{2,0,0}
    6=2^1*3^1*5^0 ——>{1,1,0}
    10=2^1*3^0*5^1 ——>{1,0,1}
    15=2^0*3^1*5^1 ——>{0,1,1}

    我们现在按照题目要求,选出若干数乘起来,
    得到的数字(我们称为W)也一定可以用2,3,5这三个质数表示

    为了辅助该数的表示,我们设一个01向量x
    xi表示第i位数字是否要选(选是1,不选是0)
    这样我们按照题目求出的数就可以如下表示了:
    这里写图片描述
    因为只有第一个数(4),第二个数(6),第三个数(10)有2这个因子,
    所以得到的W中2的指数只能由这三个数决定,其余的同理

    如果W可以被开方,显然每个质数的次数都要是偶数,即
    x2+x3=0 (mod 2)
    x2+x4=0 (mod 2)
    x3+x4=0 (mod 2)
    由于异或和数字的奇偶性有很大关系,所以上述的方程组可以变成异或方程
    x2 XOR x3=0
    x2 XOR x4=0
    x3 XOR x4=0

    这样我们就可用高斯消元优美的解决了

    最后的答案是

    2^(自由元的个数)-1

    因为每个自由元都有两种选择,但是题目不允许我们一个都不选,所以要-1

    tip

    在阵式的构造上,
    a[i][j]=1表示第j个数字有第i个质数这个因子,且该因子在第j个数中的次数是奇数
    换句换说就是,第i个质数的次数会受到第j个数的影响

    gauss消元没有固定的模板,重要的是掌握ta的思维方式

    //这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define ll long long
    
    using namespace std;
    
    int a[102][102];     //500以内的素数只有95个  
    int sshu[102],tot=0,maxp,n; 
    bool no[502];
    
    void prime(int n)
    {
        for (int i=2;i<=n;i++)
        {
            if (!no[i]) sshu[++tot]=i;
            for (int j=1;j<=tot&&sshu[j]*i<=n;j++)
            {
                no[sshu[j]*i]=1;
                if (i%sshu[j]==0) break;
            }
        }
    }
    
    int gauss(int n,int m)                     //n个未知量,m个方程 
    {
        int cnt=0;
        int now=1;
        for (int i=1;i<=n;i++)                 //枚举未知量 
        {
            int num=now;                       //消元消到了第几个方程 
            for (int j=now;j<=m;j++) 
                if (a[j][i])
                {
                    num=j;
                    break;
                }
            if (!a[num][i]) continue;
            if (now!=num)
                for (int j=1;j<=n+1;j++)
                    swap(a[now][j],a[num][j]);
            for (int j=1;j<=m;j++) 
                if (a[j][i]&&j!=now)
                    for (int k=1;k<=n+1;k++)
                        a[j][k]^=a[now][k];
            now++;
        }
        return n-now+1;
    }
    
    int main()
    {
        prime(500);
        int T;
        scanf("%d",&T);
        while (T--)
        {
            memset(a,0,sizeof(a));
            scanf("%d",&n);
            ll x;                                  //注意x的范围 
            maxp=0;                                //n个数中涉及到的最大素数 
            for (int i=1;i<=n;i++)
            {
                scanf("%lld",&x);
                for (int j=1;j<=tot&&x!=1;j++)
                    while (x%sshu[j]==0)
                    {
                        a[j][i]^=1;                //sshu[j]的系数可能有第i个数的影响 
                        x/=sshu[j];
                        maxp=max(maxp,j);
                    }
            }
    
            int ans=gauss(n,maxp);
            printf("%lld
    ",(1LL<<ans)-1); 
        }
        return 0;
    }
  • 相关阅读:
    MSSQL Rebuild(重建)索引
    网络爬虫原理
    Twitter Storm:单机环境的安装与配置
    1079 回家
    Win2003 Server磁盘配额揭密之补遗篇
    Win2003 Server磁盘配额揭密之启用篇
    编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功)
    Writing a Windows Shell Extension(marco cantu的博客)
    Android学习之一:Cygwin简介
    Linux 进程间通信(一)
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7672998.html
Copyright © 2011-2022 走看看