zoukankan      html  css  js  c++  java
  • HDU 5833 Zhu and 772002 (数论+高斯消元)

    题目链接

    题意:给定n个数,这n个数的素因子值不超过2000,从中取任意个数使其乘积为完全平方数,问有多少种取法。

    题解:开始用素筛枚举写了半天TLE了,后来队友说高斯消元才想起来,果断用模板。赛后又得知这是个原题sgu200,真坑啊。把每个数进行素因子分解,素因子a的幂为奇数则视为1,偶数则视为0,转化为从n个数中取数异或和为0有多少种取法的问题。

    AC代码:

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #define maxn 305
    using namespace std;
    typedef long long ll;
    ll T, N;
    ll beg[maxn], end[maxn], x[maxn];
    ll a[maxn][maxn];
    
    ll Gauss_XOR(ll a[maxn][maxn], ll x[maxn], ll var, ll equ)
    {
        ll row, col;
        for (row = col = 1; row <= equ && col <= var; ++row, ++col)
        {
            if (!a[row][col])
            {
                for (int i = equ; i > row; --i)
                {
                    if (a[i][col])
                    {
                        for (int j = row; j <= var + 1; ++j)
                        {
                            swap(a[i][j], a[row][j]);
                        }
                        break;
                    }
                }
            }
            if (!a[row][col])
            {
                --row;
                continue;
            }
            for (int i = row + 1; i <= equ; ++i)
            {
                if (a[i][col])
                {
                    for (int j = var + 1; j >= col; --j)
                    {
                        a[i][j] ^= a[row][j];
                    }
                }
            }
        }
        for (int i = row; i <= equ; ++i)
        {
            if (a[i][var + 1]) return -1;
        }
        if (row <= var)
        {
            return var - row + 1;
        }
        for (int i = var; i >= 1; --i)
        {
            x[i] = a[i][var + 1];
            for (int j = i + 1; j <= var; ++j)
            {
                x[i] ^= a[i][j] && x[j];
            }
        }
        return 0;
    }
    const long long mod=1000000007;
    ll prime[2050],cnt=0;
    ll isprime[2050];
    ll data[50][10];
    void get()
    {
        for(int i=0; i<=2000; i++)
            isprime[i]=1;
        for(int i=2; i<=2000; i++)
        {
            if(isprime[i]==1)
            {
                prime[cnt++]=i;
                for(int j=i+i; j<=2000; j+=i)
                    isprime[j]=0;
            }
        }
    }
    int main()
    {
        ll num;
        int cas=1;
        get();
        scanf("%lld", &T);
        while (T--)
        {
            ll equ = 0;
            memset(x, 0, sizeof (x));
            memset(a, 0, sizeof (a));
            scanf("%lld", &N);
            for(int i = 1; i <= N; ++i)
            {
                memset(data,0,sizeof(data));
                ll pos = 1;
                scanf("%lld", &num);
                ll tmp1=num,tmp2=1;
                for(int j=0; j<cnt; j++)
                {
                    int sum=0;
                    if(tmp1%prime[j]==0)
                    {
                        tmp1/=prime[j];
                        sum++;
                        while(tmp1%prime[j]==0)
                        {
                            tmp1/=prime[j];
                            sum++;
                        }
                    }
                    if(sum%2==1)
                        data[j/8][j%8]=1;
                }
                int b=305;
                int ii=0,jj=0;
                while(b--)
                {
                    if(jj==8)
                    {
                        ii++;
                        jj=0;
                    }
                    if(data[ii][jj++] & 1) a[pos][i] = 1;
                    else a[pos][i] = 0;
                    //num >>= 1;
                    ++pos;
                }
                equ = max(equ, pos - 1);
            }
            for(int i = 1; i <= 32; ++i)
                a[i][N + 1] = 0;
            ll ans = Gauss_XOR(a, x, N, equ);
            if (ans == -1) puts("-1");
            else
            {
                ll prt = 1;
                for(int i = 1; i <= ans; ++i)
                {
                    prt <<= 1;
                    prt %= mod;
                }
                printf("Case #%d:
    ",cas++);
                prt=(prt-1+mod)%mod;
                printf("%lld
    ", prt);
            }
        }
        return 0;
    }

    之前写的TLE素筛:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    const long long mod=1000000007;
    ll prime[2050],cnt=0;
    ll isprime[2050],isprime2[2050];
    ll data[300][2050];
    void get()
    {
        for(int i=0; i<=2000; i++)
            isprime[i]=1;
        for(int i=2; i<=2000; i++)
        {
            if(isprime[i]==1)
            {
                prime[cnt++]=i;
                for(int j=i+i; j<=2000; j+=i)
                    isprime[j]=0;
            }
        }
    }
    int main()
    {
        get();
        //303
        int num[cnt+5];
        int t,cas=1,a[305];
        /* ll c=1;
         for(int i=0;i<15;i++)
             c*=prime[i];
         printf("%lld
    ",b);*/
        scanf("%d",&t);
        while(t--)
        {
            int n;
            memset(a,0,sizeof(a));
            memset(data,0,sizeof(data));
            scanf("%d",&n);
            for(int i=0; i<n; i++)
                scanf("%d",&a[i]);
            sort(a,a+n);
            ll sum=0,k=-1,flag1=0;
            ll tmp1;
            for(int i=0; i<2; i++)
            {
                sum=0;
                k=-1;
                flag1=0;
                for(int j=0; j<n; j++)
                {
                    tmp1=a[j];
                    if(tmp1==-1) continue;
                    if(tmp1%prime[i]==0)
                    {
                        //cout<<tmp1<<"   *** "<<prime[i]<<endl;
                        tmp1/=prime[i];
                        sum++;
                        flag1++;
                        while(tmp1%prime[i]==0)
                        {
                            tmp1/=prime[i];
                            sum++;
                        }
                        k=j;
                    }
                    if(flag1>=2)
                    break;
                }
                //cout<<prime[i]<<"    "<<sum<<"   "<<flag1<<endl;
                if(flag1==1&&((sum%2)==1))
                    a[k]=-1;
            }
            for(int i=0; i<n; i++)
            {
                if(a[i]==-1)
                {
                    for(int j=i; j<n; j++)
                    {
                        a[j]=a[j+1];
                    }
                    i--;
                    n--;
                }
            }
            ll tmp=1;
            memset(num,0,sizeof(num));
            ll tmp2;
            for(int i=0;i<n;i++)
            {
                tmp=1;
                for(int j=0;j<cnt;j++)
                {
                    tmp2=a[i];
                    if(!tmp2) break;
                    if(tmp2%prime[j]==0&&tmp2!=0)
                    {
                        tmp2/=prime[j];
                        data[i][prime[j]]++;
                        while(tmp2%prime[j]==0)
                        {
                            tmp2/=prime[j];
                            data[i][prime[j]]++;
                        }
                        data[i][prime[j]]%=2;
                    }
                }
            }
    //        cout<<data[0][3]<<endl;
    //        cout<<data[1][3]<<endl;
    //        cout<<data[2][2]<<endl;
    //        for(int i=0;i<n;i++)
    //        {
    //            cout<<a[i]<<"  ";
    //        }cout<<endl;
            ll pre[2050];
            ll ans=-1;
            for(int i=0;i<(1<<n);i++)
            {
                memset(pre,0,sizeof(pre));
                for(int j=0;j<n;j++)
                {
                    if(i&(1<<j))
                    {
                        for(int x=2;x<=2000;x++)
                        {
                            pre[x]+=data[j][x];
                            pre[x]%=2;
                        }
                    }
                }
                int flag=0;
                for(int k=0;k<cnt;k++)
                {
                    if(pre[prime[k]]%2==1)
                    {
                        flag=1;
                        break;
                    }
                }
                if(flag==0)
                {
                    //cout<<i<<"***"<<endl;
                    ans++;
                    ans%=mod;
                }
            }
            printf("Case #%d:
    ",cas++);
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Qt passwd echoMode placeholer QString.trimmed()
    bit opt
    Linux Kernel Development系统调用
    Linux Kernel Development——列出系统中所有的进程
    Linux Kernel Development——内存管理
    Linux Kernel Development——定时器和时间管理
    Linux Kernel Development——内核同步方法
    [转]Linux 2.6中断下半部机制分析
    Linux Kernel Development——中断
    Linux Kernel Development——虚拟文件系统
  • 原文地址:https://www.cnblogs.com/Ritchie/p/5770894.html
Copyright © 2011-2022 走看看