题目连接:https://vjudge.net/contest/392610#problem/B
解题思路:
对于每个质因子,显然只有偶数和奇数的两种情况需要考虑,考虑构建异或方程组。高斯消元法一个板子下来,求出自由未知元的个数,然后就是对自由元赋值,0或者1,总共有2^k种,别忘了去掉全是0的情况,因此答案是2^k -1

代码:

#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
#define MAXN 2010
#define N 2010
#define INF 0x3f3f3f3f
typedef long long ll;


int a[N][N];//增广矩阵
int x[N];//解集
int freeX[N];//自由变元
int Gauss(int equ,int var){//返回自由变元个数
    /*初始化*/
    for(int i=0;i<=var;i++){
        x[i]=0;
        freeX[i]=0;
    }

    /*转换为阶梯阵*/
    int col=0;//当前处理的列
    int num=0;//自由变元的序号
    int row;//当前处理的行
    for(row=0;row<equ&&col<var;row++,col++){//枚举当前处理的行
        int maxRow=row;//当前列绝对值最大的行
        for(int i=row+1;i<equ;i++){//寻找当前列绝对值最大的行
            if(abs(a[i][col])>abs(a[maxRow][col]))
                maxRow=i;
        }
        if(maxRow!=row){//与第row行交换
            for(int j=row;j<var+1;j++)
                swap(a[row][j],a[maxRow][j]);
        }
        if(a[row][col]==0){//col列第row行以下全是0,处理当前行的下一列
            freeX[num++]=col;//记录自由变元
            row--;
            continue;
        }

        for(int i=row+1;i<equ;i++){
            if(a[i][col]!=0){
                for(int j=col;j<var+1;j++){//对于下面出现该列中有1的行,需要把1消掉
                    a[i][j]^=a[row][j];
                }
            }
        }
    }

    /*求解*/
    //无解:化简的增广阵中存在(0,0,...,a)这样的行,且a!=0
    for(int i=row;i<equ;i++)
        if(a[i][col]!=0)
            return -1;

    //无穷解: 在var*(var+1)的增广阵中出现(0,0,...,0)这样的行
    int temp=var-row;//自由变元有var-row个
    if(row<var)//返回自由变元数
        return temp;

    //唯一解: 在var*(var+1)的增广阵中形成严格的上三角阵
    for(int i=var-1;i>=0;i--){//计算解集
        x[i]=a[i][var];
        for(int j=i+1;j<var;j++)
            x[i]^=(a[i][j]&&x[j]);
    }
    return 0;
}
int enumFreeX(int freeNum,int var){//枚举自由元,统计有解情况下1最少的个数
    int sta=(1<<(freeNum));//自由元的状态总数
    int res=INF;
    for(int i=0;i<sta;++i){//枚举状态
        int cnt=0;
        for(int j=0;j<freeNum;j++){//枚举自由元
            if(i&(1<<j)){
                cnt++;
                x[freeX[j]]=1;
            }else
                x[freeX[j]]=0;
        }
        for(int k=var-freeNum-1;k>=0;k--){//没有自由元的最下面一行
            int index=0;
            for(index=k;k<var;index++){//在当前行找到第一个非0自由元
                if(a[k][index])
                    break;
            }
            x[index]=a[k][var];
            for(int j=index+1;j<var;++j){//向后依次计算出结果
                if(a[k][j])
                    x[index]^=x[j];
            }
            cnt+=x[index];//若结果为1,则进行统计
        }
        res=min(res,cnt);
    }
    return res;
}


//

int prime[MAXN], tot;
bool vis[MAXN];
void Prime()
{
    for(int i = 2; i <= MAXN; i++) {
        if(!vis[i]) {
            prime[++tot] = i;
        }
        for(int j = 1; j <= tot ; j++) {
            if(i * prime[j] > MAXN) break;
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;    //当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。 
        }
    }
}

ll q_pow(ll a, ll b, ll m){
    ll ans = 1;
    while(b > 0){
        if(b & 1){
            ans = ans * a % m;
        }
        a = a * a % m;
        b >>= 1; 
    } 
    return ans;
}


ll b[MAXN];

int main()
{
    ios::sync_with_stdio(false);
    Prime(); 
    int t, cas=0;
    cin>>t;
    while(t--)
    {    
        memset(a, 0, sizeof(a));
        int n;
        cin>>n;

        int equ = tot, var = n;

        for(int i = 0;  i< n; i++){
            cin>>b[i];
        }

        for(int i = 0;  i<tot; i++){
            for(int j = 0;  j < var; j++){
                while(b[j] % prime[i+1] == 0){
                    b[j] /= prime[i+1];
                    a[i][j]^=1;
                }
            }
        }


//        for(int i = 0;  i<tot; i++){
//            for(int j = 0;  j < var; j++){
//                
//                printf("%d ",a[i][j]);
//            }
//            printf("\n");
//        }


        int freeNum=Gauss(equ,var);//获取自由元


        ll ans = (q_pow(2*1LL, freeNum*1LL, MOD) - 1)%MOD;

        printf("Case #%d:\n",++cas);
        printf("%lld\n",ans);
     } 
}