Zhu and 772002 HDU - 5833 (高斯消元求异或方程组解的个数)

2024-01-14 02:32

本文主要是介绍Zhu and 772002 HDU - 5833 (高斯消元求异或方程组解的个数),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5833

题目描述:给定n个数,每个数所含质因子最大不超过2000,选取任意个(至少为1个)数字相乘,要求所得乘积为完全平方数,求共有多少种选取方案。

思路:题目都已经说每个数所含最大质因子不超过2000了,很明显是要分解质因子求解,求的2000以内的素数共303个。要想相乘组成完全平方数,只要所选取的x个数中含有的质因子都是偶数个都行,奇偶可以用10表示,1为奇数个,0为偶数个。首先需要求出每个数所含质因子及其个数,设a[i][j]表示第j个数所含质因子i的个数,0表示偶数个,1表示奇数个。x[i]表示是否选取第i个数。则只需:

a[1][1] *x[1] ^ a[1][2] * x[2] ^ ...... ^ a[1][n] * x[n] = 0

a[2][1] *x[1] ^ a[2][2] * x[2] ^ ...... ^ a[2][n] * x[n] = 0

...........

a[n][1] *x[1] ^ a[n][2] * x[2] ^ ...... ^ a[n][n] * x[n] = 0

这样很明显用高斯消元求矩阵的秩,进而求出自由变量的个数ans,那么方程组X[i]的解的个数为2^ans,注意要减去一个数都不选(即X[i]全为0的情况),故答案为2^ans-1。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int  maxn = 2000 + 10;
const int  maxt = 300 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
const int MOD = 1000000007;
ll n, m, k;
int prime[500];//素数表
bool vis[maxn];
int a[maxn][maxn];//a[i][j]表示数字j中含有所含质因子i的个数,奇数个为1,偶数个为0
ll num[maxn];
int cnt;
void getPrime(){//2000以内素数打表memset(prime, 0, sizeof prime);memset(vis, false, sizeof vis);int maxnum = 2000;cnt = 0;for(int i = 2; i <= maxnum; ++i)if(!vis[i]){prime[++cnt] = i;vis[i] = true;for(int j = i * i; j <= maxnum; j += i){vis[j] = true;}}
}
ll Gauss(){//高斯消元int i, j, k, x, y;for(i = 1, j = 1; i <= cnt && j <= n; ++j){k = i;while(k <= cnt && !a[k][j]) ++k;if(a[k][j]){swap(a[i], a[k]);for(x = i + 1; x <= cnt; ++x){if(a[x][j]){for(y = i; y <= n; ++y){a[x][y] ^= a[i][y];}}}++i;}}return (ll)n - (ll)i + 1ll;//自由变量的个数,每个自由变量可以为0也可以为1,故解的个数就是(1<<自由变量个数)
}
ll quick_pow(ll a, ll x){//快速幂ll ans = 1;while(x > 0){if(x & 1) ans = (ans * a) % MOD;x >>= 1;a = (a * a) % MOD;}return ans;
}
int main(){getPrime();int t, kase = 0;scanf("%d", &t);while(t--){scanf("%I64d", &n);ll tmp;memset(a, 0, sizeof a);for(int i = 1; i <= n; ++i){scanf("%lld", &num[i]);tmp = num[i];for(int j = 1; j <= cnt; ++j){//求每个数所含质因子及其个数if(tmp % prime[j] == 0){while(tmp > 0 && tmp % prime[j] == 0){a[j][i] ^= 1;//异或判断有奇数个还是偶数个tmp /= prime[j];}}}}ll x = Gauss();printf("Case #%d:\n", ++kase);printf("%lld\n", quick_pow(2, x) - 1);//减去全为0(也就是一个数都不选)的情况}return 0;
}/*2
3
3 3 4
3
2 2 2*/


a[i][1] *x[1] ^ a[i][2] * x[2] ^ ...... ^ a[i][n] * x[n] = 0
a[i][1] *x[1] ^ a[i][2] * x[2] ^ ...... ^ a[i][n] * x[n] = 0

这篇关于Zhu and 772002 HDU - 5833 (高斯消元求异或方程组解的个数)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/603648

相关文章

spoj705( 求不相同的子串个数)

题意:求串s的不同子串的个数 解题思路:任何子串都是某个后缀的前缀,对n个后缀排序,求某个后缀的前缀的个数,减去height[i](第i个后缀与第i-1 个后缀有相同的height[i]个前缀)。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstrin

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

hdu 1102 uva 10397(最小生成树prim)

hdu 1102: 题意: 给一个邻接矩阵,给一些村庄间已经修的路,问最小生成树。 解析: 把已经修的路的权值改为0,套个prim()。 注意prim 最外层循坏为n-1。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstri