您的位置:首页 > 其它

HDU 5833 高斯消元 异或方程组

2016-08-16 10:02 405 查看
题意:给出n个正整数,从中选出1个或者多个,使得选出来的整数乘积是完全平方数,一共有多少种选法。

思路:用01向量表示一个数,再用n个01向量来表示我们的选择,因为完全平方数要求素因子的次数一定要是偶数的,所以我们可以统计的将奇数当作1,偶数当作0,那么就是一组可以变换成oxr的方程组,最后的结果有自由变量f个,答案是2^f-1,f求解就是求n-方程组的秩,(本题不允许一个都不选,所以减去1,即去掉自由元全取0的这种情况)。

求的是方程解的个数,方程解的个数等于  2^自由变量的个数。

详解见白书 161页。

#include<bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define bug puts("***********")
using namespace std;
const int N =510;
const LL mod =1000000007;
struct Mat{
int mat

;
}sta;
int cnt=0;
int vis[2010];
int prime
;
void init(){
mem(vis,0);
for(int i=2;i<2010;i++){
if(vis[i]==0){
prime[cnt++]=i;
for(int j=i*i;j<2010;j+=i)
vis[j]=1;
}
}
}
int ran(Mat a,int n,int m){
int i=0,j=0,r;
while(i<n&&j<m){  ///第i个方程 第j个变量。
int r=i;
for(int k=i;k<n;k++){
if(a.mat[k][j]){
r=k;
break;
}
}
if(a.mat[r][j]){
if(r!=i){
for(int k=0;k<=m;k++)swap(a.mat[r][k],a.mat[i][k]);
}
for(int k=i+1;k<n;k++){
if(a.mat[k][j]){
for(int g=0;g<=m;g++)
a.mat[k][g]^=a.mat[i][g];
}
}
i++;
}
j++;
}
return i;
}
int main(){
init();///cnt 个方程。
int t,n;
int maxn=0;
scanf("%d",&t);
LL x;
int cas=1;
while(t--){
mem(sta.mat,0);
scanf("%d",&n);
for(int i=0;i<n;i++){   /// n个变量
scanf("%lld",&x);
for(int j=0;j<cnt;j++){
while(x%prime[j]==0){
maxn=max(maxn,j);
x/=prime[j];
sta.mat[j][i]^=1;
}
}
}

int r=ran(sta,maxn+1,n);
LL num=1;
for(int i=1;i<=n-r;i++)
num=num*2%mod;
printf("Case #%d:\n%lld\n",cas++,(num+mod-1)%mod);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: