C. Square Subsets

4 篇文章 0 订阅
1 篇文章 0 订阅

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 ) ;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值