码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 895C Square Subsets(状压DP 或 异或线性基)

时间:2017-12-08 14:16:24      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:一个   test   contest   long   ble   题目   sizeof   printf   problem   

题目链接  Square Subsets

这是白书原题啊

先考虑状压DP的做法

2到70总共19个质数,所以考虑状态压缩。

因为数据范围是70,那么我们统计出2到70的每个数的个数然后从2考虑到70。

设dp[x][mask]为考虑到x这个数的时候,x这个数和之前的所有数中,选出某些数,他们的乘积分解质因数,所有的指数对2取模之后,

状态为mask的方案数。

然后就可以转移了……这个状压DP花了我好几个小时……真是弱啊

哦对最后还要特判1的情况。

每个1选或不选都可以,然后考虑只选1的情况,累加即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const LL mod = 1e9 + 7;
const int N  = 3e6 + 10;
const int M  = 1e5 + 10;

int c[101], p[30], m[101];
int n, x, cnt, now, all;
bool flag;
LL two[M], f[2][N];

void up(LL &a, LL b) { a = (a + b) % mod;}

void init(){
	two[0] = 1;
	rep(i, 1, 100000) two[i] = two[i - 1] * 2 % mod;

	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", &x), ++c[x];

	rep(i, 2, 70){
		flag = true;
		rep(j, 2, i - 1) if (i % j == 0){
			flag = false;
			break;
		}
		if (flag) p[cnt++] = i;
	}

	rep(i, 1, 70){
		int y = i;
		rep(j, 0, cnt - 1){
			int tt = 0;
			while (y % p[j] == 0) y /= p[j], ++tt;
			if (tt & 1) m[i] |= (1 << j);
		}
	}
}

int main(){

	init();
	all = (1 << cnt) - 1;
	rep(i, 2, 70){
		if (c[i] == 0) continue;
		memset(f[now ^ 1], 0, sizeof f[now ^ 1]);
		LL a1 = two[c[i] - 1], a2 = (a1 - 1 + mod) % mod;

		up(f[now ^ 1][m[i]], a1);
		up(f[now ^ 1][0], a2);

		rep(mask, 0, all) up(f[now ^ 1][mask ^ m[i]], f[now][mask] * a1 % mod);
		rep(mask, 0, all) up(f[now ^ 1][mask], f[now][mask] * a2 % mod);
		rep(mask, 0, all) up(f[now ^ 1][mask], f[now][mask]);
		now ^= 1;
	}

	LL ans = f[now][0];
	ans = (ans * two[c[1]]) % mod;
	up(ans, (two[c[1]] - 1 + mod) % mod);
	printf("%lld\n", ans);
	return 0;
}

 

还有一种就是考虑异或线性基的做法。

如果一个数可以被当前线性基中的数表示出来,那么这个数就相当于一个完全平方数。

选与不选两种状态。

令最后线性基中的数的个数为$x$

最后答案就是$2^{n - x} - 1$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const LL mod = 1e9 + 7;
const int N  = 3e6 + 10;
const int M  = 1e5 + 10;

int c[101], p[30], m[101];
int n, x, cnt, now, all;
bool flag;
LL two[M], f[2][N];

void up(LL &a, LL b) { a = (a + b) % mod;}

void init(){
	two[0] = 1;
	rep(i, 1, 100000) two[i] = two[i - 1] * 2 % mod;

	scanf("%d", &n);
	rep(i, 1, n) scanf("%d", &x), ++c[x];

	rep(i, 2, 70){
		flag = true;
		rep(j, 2, i - 1) if (i % j == 0){
			flag = false;
			break;
		}
		if (flag) p[cnt++] = i;
	}

	rep(i, 1, 70){
		int y = i;
		rep(j, 0, cnt - 1){
			int tt = 0;
			while (y % p[j] == 0) y /= p[j], ++tt;
			if (tt & 1) m[i] |= (1 << j);
		}
	}
}

int main(){

	init();
	all = (1 << cnt) - 1;
	rep(i, 2, 70){
		if (c[i] == 0) continue;
		memset(f[now ^ 1], 0, sizeof f[now ^ 1]);
		LL a1 = two[c[i] - 1], a2 = (a1 - 1 + mod) % mod;

		up(f[now ^ 1][m[i]], a1);
		up(f[now ^ 1][0], a2);

		rep(mask, 0, all) up(f[now ^ 1][mask ^ m[i]], f[now][mask] * a1 % mod);
		rep(mask, 0, all) up(f[now ^ 1][mask], f[now][mask] * a2 % mod);
		rep(mask, 0, all) up(f[now ^ 1][mask], f[now][mask]);
		now ^= 1;
	}

	LL ans = f[now][0];
	ans = (ans * two[c[1]]) % mod;
	up(ans, (two[c[1]] - 1 + mod) % mod);
	printf("%lld\n", ans);
	return 0;
}

 

Codeforces 895C Square Subsets(状压DP 或 异或线性基)

标签:一个   test   contest   long   ble   题目   sizeof   printf   problem   

原文地址:http://www.cnblogs.com/cxhscst2/p/8004857.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!