题目连接: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);
}
}

京公网安备 11010502036488号