标签:
Description
给出n个数,每个数都是由前t个素数组成的,问成绩为完全平方数的子集有多少?
完全平方数,也就是所成绩的所有素数组成都是偶数个,由此可以列出方程组,方程为Map[i][j]第j个数的第i个素数个数是不是偶数,偶数为0,奇数为1,结果全部为0,找出一共有多少组,也就是说找出自由元数num1,然后2^num1 - 1,减去全为0的一组,就是结果。
注意1,求自由元的时候不能直接在j == n的时候计数,那样在n*n的矩阵中可以,如果不是的话要用n-i
注意2,求出的自由元会很大,2^num1是个大数,所以要模拟一下,因为2的倍数的最后一位是1,2,4,8,6,2,....所以最后直接将最后一位减一就可以了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int vis[1100] , prim[1100] , cnt ;
int Map[110][110] , a[110] ;
int s[10000] ;
void get_prim()
{
int i , j ;
memset(vis,0,sizeof(vis)) ;
memset(prim,0,sizeof(prim)) ;
cnt = 0 ;
for(i = 2 ; i < 1000 ; i++)
{
if( !vis[i] )
{
prim[cnt++] = i ;
}
for(j = 0 ; j < cnt ; j++)
{
if( prim[j]*i >= 1000 ) break ;
vis[ prim[j]*i ] = 1 ;
if( i % prim[j] == 0 ) break ;
}
}
return ;
}
void swap1(int p,int q,int m)
{
int i , temp ;
temp = a[p] ;
a[p] = a[q] ;
a[q] = temp ;
for(i = 0 ; i < m ; i++)
{
temp = Map[p][i] ;
Map[p][i] = Map[q][i] ;
Map[q][i] = temp ;
}
return ;
}
int gauss(int n,int m)
{
int i , j , k , t , num1 = 0;
for(i = 0 , t = 0 ; i < n && t < m ; i++ , t++)
{
for(j = i ; j < n ; j++)
if( Map[j][t] )
break ;
if( j == n )
{
i-- ;
continue ;
}
if( i != j )
swap1(i,j,m) ;
for(j = i+1 ; j < n ; j++)
{
if( Map[j][t] == 0 ) continue ;
a[j] ^= a[i] ;
for(k = t ; k < m ; k++)
{
Map[j][k] ^= Map[i][k] ;
}
}
}
return m - i ;
}
int main()
{
int t , m , i , j , x , num1 ;
get_prim() ;
memset(Map,0,sizeof(Map)) ;
scanf("%d %d", &t, &m) ;
for(j = 0 ; j < m ; j++)
{
scanf("%d", &x) ;
for(i = 0 ; i < t ; i++)
{
a[i] = 0 ;
num1 = 0 ;
while( x % prim[i] == 0 )
{
num1++ ;
x /= prim[i] ;
}
Map[i][j] = num1 % 2 ;
}
}
num1 = gauss(t,m) ;
s[0] = 1 ;
cnt = 1 ;
int temp , k ;
for(i = 0 ; i < num1 ; i++)
{
temp = 0 ;
for(j = 0 ; j < cnt ; j++)
{
k = s[j]*2 + temp ;
s[j] = k%10 ;
temp = k/10 ;
}
if( temp != 0 )
s[cnt++] = temp ;
}
s[0] -= 1 ;
for(i = cnt-1 ; i >= 0 ; i--)
{
printf("%d", s[i]) ;
}
printf("\n") ;
return 0;
}
sgu200--Cracking RSA(高斯消元问题5,求乘积为完全平方数的种数)
标签:
原文地址:http://blog.csdn.net/winddreams/article/details/43190483