题意:给你一个数列,然后找任意数量的数字(除了空集),使得他们的乘机为一个数的平方
我们发现元素最大70,所以我们可以从这里入手,平方数有个性质就是它的所有质因子的指数为偶数
比如:36 = 2*2*3*3;然后我们可以写一个状态压缩dp,第一维表示小于等于第一维的所有数字,第二
维表示到达的状态,那最终的结果就是dp[70][0],dp[i]和dp[i-1]的区别就是,你有没有取到i这个数字,你会发现,
如果你取偶数个i的话,对于状态是不影响的,因为偶数个异或就是零,奇数个的话就是它的本身,里面还有一个性质,
就是C(n,0)+C(n,2) + ... = C(n,1)+C(n,3)+ ...,你可以取a=1,b=-1就很好证明,还有因为它们的和就是
2的n次方,参考https://zhidao.baidu.com/question/2268538776712429868.html(来自百度),所以无论取奇数个还是偶数,都有
2的n-1次方种,所以转移方程为if(cnt【i】) dp【i】【j】= (dp【i-1】【j】+ dp【i-1】【s【i】^ j】)*m【cnt【i】-1】;else dp【i】【j】 =dp【i-1】【j】;(还没加入取模运算)
下面直接看代码:
#include<bits/stdc++.h> #define de(x) cout<<#x<<"="<<x<<endl; #define dd(x) cout<<#x<<"="<<x<<" "; #define rep(i,a,b) for(int i=a;i<(b);++i) #define repd(i,a,b) for(int i=a;i>=(b);--i) #define mt(a,b) memset(a,b,sizeof(a)) #define fi first #define se second #define inf 0x7f #define pii pair<int,int> #define pdd pair<double,double> #define pdi pair<double,int> #define mp(u,v) make_pair(u,v) #define sz(a) a.size() #define ull unsigned long long #define ll long long #define pb push_back #define PI acos(-1.0) const int mod = 1e9+7; const int maxn = 1e5+5; const double EPS = 1e-6; using namespace std; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } int a[maxn]; int s[maxn]; int prime[maxn]; ll m[maxn]; int dp[82][1<<19]; int cnt[82]; bool is_prime(int x){ for(int i=2;i*i<=x;++i) if(x%i==0) return false; return true; } void init(){ mt(cnt,0); int cntt = 0; rep(i,2,71){ if(is_prime(i)) prime[cntt++] = i; } m[0] = 1; rep(i,1,maxn) m[i] = (m[i-1]*2)%mod; rep(i,1,71){ int t = i; rep(j,0,19){ while(t&&t%prime[j]==0){ t/=prime[j]; s[i] = s[i]^(1<<j); } } } } int main() { init(); int n; scanf("%d",&n); rep(i,0,n){ scanf("%d",&a[i]); cnt[a[i]]++; } dp[0][0] = 1; rep(i,1,71){ rep(j,0,(1<<19)){ if(cnt[i]){ dp[i][j] = ((dp[i-1][j] + dp[i-1][j^s[i]]) %mod) * m[cnt[i]-1]%mod; }else dp[i][j] = dp[i-1][j]; } } cout<<((dp[70][0]-1+mod)%mod)<<endl; return 0; }