C. Square Subsets

C. Square Subsets

題目鏈接
給一個序列ai,長度n,問有多少種方法可以選一些數字出來,且使得這些數字乘積是一個平方數。
n<=1e5 , ai<=70
任意一個平方數可以表示爲p1^a1 * p2^a2 * ……其中p1表示質數,a1是一個偶數,且我們不關心具體是多少隻需要知道是奇偶即可,那麼可以直接用01來表示。
觀察到ai比較小,我們直接把70以內的數字拆分成質因子表示形式,然後用二進制來表示它的冪,然後狀壓計數即可。

#include<bits/stdc++.h>
using namespace std;
#define LONG long long
#define clr0(x) memset(x , 0 , sizeof x)
const  LONG MOD = 1e9 + 7 ;
int take[77] ;
int pw[77] ;
int ss[77] ;
LONG  POW[100100] ;
int  f[73][(1<<19 ) +100] ;
LONG Qpow(LONG a , int b )
{
    return POW[b] ;
}
int main()
{
    POW[0] = 1 ;
    for(int i = 1 ;i <= 100000 ; ++ i)
        POW[i] = POW[i-1] * 2  %MOD ;
    int T = -1 ;
    for(int i = 2 ; i <= 70 ; ++ i)
    {
        int judge = 0 ;
        for(int j = 2;j < i ; ++ j)
            if(i %j ==0 ) judge = 1;
        if(!judge )
        {
            T ++ ;pw[i] = (1<< T )  ;
        }
    }
    for(int i = 2 ; i <= 70 ; ++ i)
    {
        int tmp= i ;ss[i] = 0 ;
        for(int j = 2;tmp > 1;)
        {
            if(tmp % j == 0)
            {
                tmp /= j ;
                ss[i] ^= pw[j] ;
                j = 2;
            }
            else j ++ ;
        }
    }
    clr0(take) ;
    int n , a ;
    scanf("%d",&n) ;
    int tot =0  ;
    for(int i = 1; i<= n ; ++ i)
    scanf("%d",&a) , take[a] ++ ;
    clr0(f) ;
    f[0][0] = 1;int p = 0;
    for(int i = 2 ; i <= 70 ; ++ i)
    {
        if(take[i] <= 0 ) continue ;
        p ++ ;
        for(int j = 0 ; j < (1 <<19 ) ; ++ j )
        {
            f[p][j] += (int ) (  Qpow( 2, take[i] - 1  )   * f[p-1][j] % MOD );
            f[p][j^ss[i]] += (int )( Qpow( 2 , take[i] -1 ) * f[p-1][j ] % MOD ) ;
        }
    }
    printf("%lld\n" , Qpow(2 , take[1] ) * f[p][0] % MOD - 1 ) ;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章