题意:给n个数,每个数的素数因子不大于2000,让你从其中选则大于等于1个数相乘之后的结果为完全平方数
思路:
- 小于等于2000的素数一共也只有305个
- 一个数,如果他某个素数因子的幂为偶,那这个素数的可以不用考虑;如果幂为奇数,那这个素数就应当被考虑如何与其他数凑成幂为偶数。例如12,可以表示为2^2*3,2的幂次为2,3的幂次为1,所以,如果要和其他数相乘为完全平方数,那么一定要与素数因子3为奇次的合并
- 那么根据上面两条,我们可以列出方程:x1*a11+x2*a12+...+xn*a1n=0;x为解,如果aii取为1,不取为0;aii表示ai的第i个素数因子是否为奇,是为1,否则为0,(素数按从小到大排序,依次为2,3,5,7...)
- 答案即为2^(x中自由元的个数)-1
/************************************************************** Problem:hdu 5833 Zhu and 772002 User: youmi Language: C++ Result: Accepted Time: Memory: ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <deque> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d ",a) #define ptlld(a) printf("%I64d ",a) #define rep(i,from,to) for(int i=from;i<=to;i++) #define irep(i,to,from) for(int i=to;i>=from;i--) #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define lson (step<<1) #define rson (lson+1) #define eps 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl const double pi=4*atan(1.0); using namespace std; typedef long long ll; template <class T> inline void read(T &n) { char c; int flag = 1; for (c = getchar(); !(c >= '0' && c <= '9' || c == '-'); c = getchar()); if (c == '-') flag = -1, n = 0; else n = c - '0'; for (c = getchar(); c >= '0' && c <= '9'; c = getchar()) n = n * 10 + c - '0'; n *= flag; } ll Pow(ll base, ll n, ll mo) { if (n == 0) return 1; if (n == 1) return base % mo; ll tmp = Pow(base, n >> 1, mo); tmp = (ll)tmp * tmp % mo; if (n & 1) tmp = (ll)tmp * base % mo; return tmp; } //*************************** int n; const ll mod=1000000007; const int maxn=50010; ll prime[maxn]; bool isprime[maxn*20]; int tot; int a[400][400]; int x[400]; int fre[400]; int index; int tt=305; void prim()//素数筛法 { tot=0; memset(isprime,true,sizeof(isprime)); prime[tot++]=2; for(int i=3;i<maxn;i+=2) { if(isprime[i]) { prime[tot++]=i; for(ll j=i;1ll*i*j<1ll*maxn;j+=2) isprime[i*j]=false; } } } void solve(int i,ll x)//判断x有哪些素数因子的幂为奇 { int cnt=0; rep(j,0,tot) { cnt=0; if(x%prime[j]==0) { while(x%prime[j]==0) { cnt++; x/=prime[j]; } } if(cnt%2) a[i][j]=1; if(x==1) break; } } void debug(int rw,int cl) { rep(i,0,rw-1) { rep(j,0,cl-1) printf("%d ",a[i][j]); printf(" "); } } int gauss(int rw,int cl)//高斯消元法,01异或 { int i,j,k; int mx=0; for(i=0,j=0;i<rw&&j<cl-1;i++,j++) { mx=i; for(k=i;k<rw;k++) { if(abs(a[k][j])>abs(a[mx][j])) mx=k; } if(mx!=i) { for(k=j;k<cl;k++) swap(a[mx][k],a[i][k]); } if(a[i][j]==0) { i--; continue; } for(k=i+1;k<rw;k++) { if(a[k][j]!=0) { for(int t=j;t<cl;t++) { a[k][t]^=a[i][t]; } } } } if(i<rw) { for(k=i-1;k>=0;k--) { int num=0; for(int t=0;t<cl;t++) { if(a[k][t]!=0&&fre[t]) num++,index=t; } if(num>1) continue; int temp=a[k][cl-1]; for(int t=0;t<cl-1;t++) if(a[k][t]!=0&&index!=t) temp^=a[k][t]&&x[t]; x[k]=temp&&a[k][k]; fre[index]=0; } return rw-i; } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif prim(); int T; scanf("%d", &T); for (int kase = 1;kase <= T;kase++) { int n; scanf("%d", &n); zeros(a); zeros(x); memset(fre,1,sizeof(fre)); for (int i=0;i<n;i++) { long long x; scanf("%I64d", &x); solve(i,x); } ll ans=gauss(n,tt); ans=(Pow(2,ans,mod)-1+mod)%mod; printf("Case #%d: %I64d ", kase,ans); } return 0; }