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:\n",cas++);
            prt=(prt-1+mod)%mod;
            printf("%lld\n", 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\n",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:\n",cas++);
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2016-08-14 20:02  Ritchie丶  阅读(522)  评论(0编辑  收藏  举报