国庆打了场组队 效果还不错 季军 现在发下题解
A:
高精度模拟即可 与n互素的数不会离n/2太远 直接暴力
代码:
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
using namespace std;
//compare比较函数:相等返回0,大于返回1,小于返回-1
int compare(string str1, string str2) {
if (str1.length() > str2.length())
return 1;
else if (str1.length() < str2.length())
return -1;
else
return str1.compare(str2);
}
//高精度加法
//只能是两个正数相加
string add(string str1, string str2) //高精度加法
{
string str;
int len1 = str1.length();
int len2 = str2.length();
//前面补0,弄成长度相同
if (len1 < len2) {
for (int i = 1; i <= len2 - len1; i++)
str1 = "0" + str1;
} else {
for (int i = 1; i <= len1 - len2; i++)
str2 = "0" + str2;
}
len1 = str1.length();
int cf = 0;
int temp;
for (int i = len1 - 1; i >= 0; i--) {
temp = str1[i] - '0' + str2[i] - '0' + cf;
cf = temp / 10;
temp %= 10;
str = char(temp + '0') + str;
}
if (cf != 0)
str = char(cf + '0') + str;
return str;
}
//高精度减法
//只能是两个正数相减,而且要大减小
string sub(string str1, string str2) //高精度减法
{
string str;
int tmp = str1.length() - str2.length();
int cf = 0;
for (int i = str2.length() - 1; i >= 0; i--) {
if (str1[tmp + i] < str2[i] + cf) {
str = char(str1[tmp + i] - str2[i] - cf + '0' + 10) + str;
cf = 1;
} else {
str = char(str1[tmp + i] - str2[i] - cf + '0') + str;
cf = 0;
}
}
for (int i = tmp - 1; i >= 0; i--) {
if (str1[i] - cf >= '0') {
str = char(str1[i] - cf) + str;
cf = 0;
} else {
str = char(str1[i] - cf + 10) + str;
cf = 1;
}
}
str.erase(0, str.find_first_not_of('0')); //去除结果中多余的前导0
return str;
}
//高精度乘法
//只能是两个正数相乘
string mul(string str1, string str2) {
string str;
int len1 = str1.length();
int len2 = str2.length();
string tempstr;
for (int i = len2 - 1; i >= 0; i--) {
tempstr = "";
int temp = str2[i] - '0';
int t = 0;
int cf = 0;
if (temp != 0) {
for (int j = 1; j <= len2 - 1 - i; j++)
tempstr += "0";
for (int j = len1 - 1; j >= 0; j--) {
t = (temp * (str1[j] - '0') + cf) % 10;
cf = (temp * (str1[j] - '0') + cf) / 10;
tempstr = char(t + '0') + tempstr;
}
if (cf != 0)
tempstr = char(cf + '0') + tempstr;
}
str = add(str, tempstr);
}
str.erase(0, str.find_first_not_of('0'));
return str;
}
//高精度除法
//两个正数相除,商为quotient,余数为residue
//需要高精度减法和乘法
void div(string str1, string str2, string "ient, string &residue) {
quotient = residue = ""; //清空
if (str2 == "0") //判断除数是否为0
{
quotient = residue = "ERROR";
return;
}
if (str1 == "0") //判断被除数是否为0
{
quotient = residue = "0";
return;
}
int res = compare(str1, str2);
if (res < 0) {
quotient = "0";
residue = str1;
return;
} else if (res == 0) {
quotient = "1";
residue = "0";
return;
} else {
int len1 = str1.length();
int len2 = str2.length();
string tempstr;
tempstr.append(str1, 0, len2 - 1);
for (int i = len2 - 1; i < len1; i++) {
tempstr = tempstr + str1[i];
tempstr.erase(0, tempstr.find_first_not_of('0'));
if (tempstr.empty())
tempstr = "0";
for (char ch = '9'; ch >= '0'; ch--) //试商
{
string str, tmp;
str = str + ch;
tmp = mul(str2, str);
if (compare(tmp, tempstr) <= 0) //试商成功
{
quotient = quotient + ch;
tempstr = sub(tempstr, tmp);
break;
}
}
}
residue = tempstr;
}
quotient.erase(0, quotient.find_first_not_of('0'));
if (quotient.empty())
quotient = "0";
}
string gcd(string a, string b) {
if (b.empty())
return a;
string s, y;
div(a, b, s, y);
//cout<<a<<" "<<b<<" "<<s<<" "<<y<<endl;
return gcd(b, y);
}
int main() {
ios::sync_with_stdio(false);
string n, f1, f2;
while (cin >> n) {
div(n, "2", f1, f2);
while (1) {
if (gcd(n, f1) == "1")
break;
f1 = sub(f1, "1");
}
cout << f1 << endl;
}
return 0;
}
B:
上下界无源无汇网络流 不能再模版了…
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cassert>
#include<vector>
#include<set>
#include<map>
#include<queue>
using namespace std;
const int MAX = 100005;
const int INF = 1000000000;
struct EDGE {
int v, c, next;
} edge[1000000];
int E, head[MAX];
int gap[MAX], cur[MAX];
int pre[MAX], dis[MAX];
int in[225], low[50000];
void add_edge(int s, int t, int c, int cc) {
edge[E].v = t;
edge[E].c = c;
edge[E].next = head[s];
head[s] = E++;
edge[E].v = s;
edge[E].c = cc;
edge[E].next = head[t];
head[t] = E++;
}
int min(int a, int b) {
return (a == -1 || b < a) ? b : a;
}
int SAP(int s, int t, int n) {
memset(gap, 0, sizeof(gap));
memset(dis, 0, sizeof(dis));
int i;
for (i = 0; i < n; i++)
cur[i] = head[i];
int u = pre[s] = s, maxflow = 0, aug = -1, v;
gap[0] = n;
while (dis[s] < n) {
loop: for (i = cur[u]; i != -1; i = edge[i].next) {
v = edge[i].v;
if (edge[i].c > 0 && dis[u] == dis[v] + 1) {
aug = min(aug, edge[i].c);
pre[v] = u;
cur[u] = i;
u = v;
if (u == t) {
for (u = pre[u]; v != s; v = u, u = pre[u]) {
edge[cur[u]].c -= aug;
edge[cur[u] ^ 1].c += aug;
}
maxflow += aug;
aug = -1;
}
goto loop;
}
}
int mindis = n;
for (i = head[u]; i != -1; i = edge[i].next) {
v = edge[i].v;
if (edge[i].c > 0 && dis[v] < mindis) {
cur[u] = i;
mindis = dis[v];
}
}
if ((--gap[dis[u]]) == 0)
break;
gap[dis[u] = mindis + 1]++;
u = pre[u];
}
return maxflow;
}
bool solve(int n) {
for (int i = 1; i <= n; i++) {
if (in[i] > 0)
add_edge(0, i, in[i], 0);
if (in[i] < 0)
add_edge(i, n + 1, -in[i], 0);
}
SAP(0, n + 1, n + 2);
for (int i = head[0]; i != -1; i = edge[i].next) //从源点出发的边都满流
{
if (edge[i].c)
return false;
}
return true;
}
int main() {
int n, m, a, b, c;
while (~scanf("%d%d", &n, &m)) {
E = 0;
memset(head, -1, sizeof(head));
memset(in, 0, sizeof(in));
for (int i = 0; i < m; i++) {
scanf("%d%d%d%d", &a, &b, &low[i], &c);
in[a] -= low[i], in[b] += low[i];
add_edge(a, b, c - low[i], 0);
}
if (solve(n)) {
printf("YES\n");
for (int i = 0; i < m; i++)
printf("%d\n", edge[(i << 1) ^ 1].c + low[i]); //反向的流即自由流,再加上下界的流
} else
printf("NO\n");
}
return 0;
}
C:
题可以转化为树上选尽量多的边 选出的边之间没有公共点
树形dp可解
我用dp[i][0.1]表示i这个点的子树的最大值 1表示i点与子树中的点匹配了 0表示没有 我用dp[i][2]表示dp[i][0.1]中的大者 那么转移方程可以很容易的写出
dp[i][0] = sum(dp[v][2]) 其中v表示i的儿子 dp[i][1] = sum(dp[v][2]) - dp[v][2] + dp[v][0] + 1那么这时i和v匹配了
dp的同时记录匹配是很容易的 然后倒着推回去 就可以打印方案了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
#define N 500010
#define mp(x,y) make_pair(x,y)
int n;
int dp[N][3], pre[N], ans[N];
int head[N], tot;
struct edge {
int v, next;
} ed[N];
int qu[N];
pair<int, int> que[N];
void add(int u, int v) {
ed[tot].v = v;
ed[tot].next = head[u];
head[u] = tot++;
}
void bfs() {
int l = 1, r = 2, u, i;
qu[1] = 1;
while (l < r) {
u = qu[l++];
for (i = head[u]; ~i; i = ed[i].next)
qu[r++] = ed[i].v;
}
}
int main() {
int i, j, k, tmp;
while (~scanf("%d", &n)) {
tot = 0;
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
memset(pre, 0, sizeof(pre));
memset(ans, 0, sizeof(ans));
for (i = 2; i <= n; i++) {
scanf("%d", &j);
add(j, i);
}
bfs();
for (i = n; i >= 1; i--) {
k = 0;
for (j = head[i]; ~j; j = ed[j].next)
k += dp[ed[j].v][2];
dp[i][0] = k;
for (j = head[i]; ~j; j = ed[j].next) {
int v = ed[j].v;
tmp = k - dp[v][2] + dp[v][0] + 1;
if (tmp > dp[i][1]) {
pre[i] = v;
dp[i][1] = tmp;
}
}
dp[i][2] = max(dp[i][0], dp[i][1]);
}
printf("%d\n", dp[1][2] * 1000);
int l = 1, r = 2;
pair<int, int> u, v;
if (dp[1][2] == dp[1][1])
que[1] = mp(1,1);
else
que[1] = mp(1,0);
while (l < r) {
u = que[l++];
for (i = head[u.first]; ~i; i = ed[i].next) {
v.first = ed[i].v;
if (v.first == pre[u.first] && u.second)
v.second = 0;
else {
if (dp[v.first][2] == dp[v.first][0])
v.second = 0;
else
v.second = 1;
}
que[r++] = v;
}
if (u.second)
ans[pre[u.first]] = 1;
}
for (i = j = 1; i <= n; i++) {
if (ans[i]) {
if (j)
j = 0;
else
printf(" ");
printf("%d", i);
}
}
printf("\n");
return 0;
}
}
D:
我不知道什么题 队友说先记个数然后求个和… 反正我就这么写了- -b
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long LL;
#define inf ((1U<<31)-1)
#define N 10010
int n, m;
LL ans;
int x[N];
int main() {
int i, u, v;
while (~scanf("%d%d", &n, &m)) {
memset(x, 0, sizeof(x));
ans = 0;
for (i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
x[u]++;
x[v]++;
}
for (i = 1; i <= n; i++)
ans += (LL) (x[i]) * x[i];
printf("%lld\n", ans);
}
return 0;
}
E:
一开始以为这题是找循环节 后来发现循环节可能不存在
m很小 所以我们可以利用状压打表 这样形成了一个矩阵 矩阵中(i,j)=1表示能从i状态转到j状态 我们发现这个矩阵是始终不变的 换句话说就是初始状态根据这个矩阵做n次操作 这种事明显可以快速幂来搞 正好前面写过高精度 拿来直接改 1A神马的还是稳稳地 ~~
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
string n;
int m, p;
int k[32][32];
int bin[10];
//高精度
//compare比较函数:相等返回0,大于返回1,小于返回-1
int compare(string str1, string str2) {
if (str1.length() > str2.length())
return 1;
else if (str1.length() < str2.length())
return -1;
else
return str1.compare(str2);
}
//高精度加法
//只能是两个正数相加
string add(string str1, string str2) //高精度加法
{
string str;
int len1 = str1.length();
int len2 = str2.length();
//前面补0,弄成长度相同
if (len1 < len2) {
for (int i = 1; i <= len2 - len1; i++)
str1 = "0" + str1;
} else {
for (int i = 1; i <= len1 - len2; i++)
str2 = "0" + str2;
}
len1 = str1.length();
int cf = 0;
int temp;
for (int i = len1 - 1; i >= 0; i--) {
temp = str1[i] - '0' + str2[i] - '0' + cf;
cf = temp / 10;
temp %= 10;
str = char(temp + '0') + str;
}
if (cf != 0)
str = char(cf + '0') + str;
return str;
}
//高精度减法
//只能是两个正数相减,而且要大减小
string sub(string str1, string str2) //高精度减法
{
string str;
int tmp = str1.length() - str2.length();
int cf = 0;
for (int i = str2.length() - 1; i >= 0; i--) {
if (str1[tmp + i] < str2[i] + cf) {
str = char(str1[tmp + i] - str2[i] - cf + '0' + 10) + str;
cf = 1;
} else {
str = char(str1[tmp + i] - str2[i] - cf + '0') + str;
cf = 0;
}
}
for (int i = tmp - 1; i >= 0; i--) {
if (str1[i] - cf >= '0') {
str = char(str1[i] - cf) + str;
cf = 0;
} else {
str = char(str1[i] - cf + 10) + str;
cf = 1;
}
}
str.erase(0, str.find_first_not_of('0')); //去除结果中多余的前导0
return str;
}
//高精度乘法
//只能是两个正数相乘
string mul(string str1, string str2) {
string str;
int len1 = str1.length();
int len2 = str2.length();
string tempstr;
for (int i = len2 - 1; i >= 0; i--) {
tempstr = "";
int temp = str2[i] - '0';
int t = 0;
int cf = 0;
if (temp != 0) {
for (int j = 1; j <= len2 - 1 - i; j++)
tempstr += "0";
for (int j = len1 - 1; j >= 0; j--) {
t = (temp * (str1[j] - '0') + cf) % 10;
cf = (temp * (str1[j] - '0') + cf) / 10;
tempstr = char(t + '0') + tempstr;
}
if (cf != 0)
tempstr = char(cf + '0') + tempstr;
}
str = add(str, tempstr);
}
str.erase(0, str.find_first_not_of('0'));
return str;
}
//高精度除法
//两个正数相除,商为quotient,余数为residue
//需要高精度减法和乘法
void div(string str1, string str2, string "ient, string &residue) {
quotient = residue = ""; //清空
if (str2 == "0") //判断除数是否为0
{
quotient = residue = "ERROR";
return;
}
if (str1 == "0") //判断被除数是否为0
{
quotient = residue = "0";
return;
}
int res = compare(str1, str2);
if (res < 0) {
quotient = "0";
residue = str1;
return;
} else if (res == 0) {
quotient = "1";
residue = "0";
return;
} else {
int len1 = str1.length();
int len2 = str2.length();
string tempstr;
tempstr.append(str1, 0, len2 - 1);
for (int i = len2 - 1; i < len1; i++) {
tempstr = tempstr + str1[i];
tempstr.erase(0, tempstr.find_first_not_of('0'));
if (tempstr.empty())
tempstr = "0";
for (char ch = '9'; ch >= '0'; ch--) //试商
{
string str, tmp;
str = str + ch;
tmp = mul(str2, str);
if (compare(tmp, tempstr) <= 0) //试商成功
{
quotient = quotient + ch;
tempstr = sub(tempstr, tmp);
break;
}
}
}
residue = tempstr;
}
quotient.erase(0, quotient.find_first_not_of('0'));
if (quotient.empty())
quotient = "0";
}
//快速幂
const int mat_n = 32;
void matrix_mul(int a[][mat_n], int b[][mat_n]) {
int c[mat_n][mat_n];
int i, j, k;
for (i = 0; i < mat_n; i++) {
for (j = 0; j < mat_n; j++) {
c[i][j] = 0;
for (k = 0; k < mat_n; k++) {
c[i][j] = (c[i][j] + (a[i][k] * b[k][j]) % p) % p;
}
}
}
for (i = 0; i < mat_n; i++)
for (j = 0; j < mat_n; j++)
a[i][j] = c[i][j];
}
void matrix_power(int s[][mat_n]) {
int ans[mat_n][mat_n];
memset(ans, 0, sizeof(ans));
int i, j;
for (i = 0; i < mat_n; i++)
ans[i][i] = 1;
string sh, yu;
while (compare(n, "0") != 0) {
div(n, "2", sh, yu);
if (yu == "1")
matrix_mul(ans, s);
n = sh;
matrix_mul(s, s);
}
for (i = 0; i < mat_n; i++)
for (j = 0; j < mat_n; j++)
s[i][j] = ans[i][j];
}
int main() {
ios::sync_with_stdio(false);
int i, j, f, flag;
bin[0] = 1;
for (f = 1; f < 10; f++)
bin[f] = bin[f - 1] << 1;
while (cin >> n >> m >> p) {
for (i = 0; i < bin[m]; i++) {
for (j = 0; j < bin[m]; j++) {
flag = 1;
for (f = 0; f < m - 1; f++) {
if (((i & bin[f]) == (j & bin[f])
&& (i & bin[f + 1]) == (j & bin[f + 1])
&& ((i & bin[f]) << 1) == (j & bin[f + 1]))) {
flag = 0;
break;
}
}
k[i][j] = flag;
//printf("%d ", flag);
}
//printf("\n");
}
n = sub(n, "1");
matrix_power(k);
f = 0;
for (i = 0; i < bin[m]; i++) {
for (j = 0; j < bin[m]; j++)
f += k[i][j];
}
printf("%d\n", f % p);
}
return 0;
}
F:
唯一一道没做出的题 题解看这http://www.cppblog.com/Yuan/archive/2010/05/02/114163.html
当时我们的思路就卡在“将视角当作边权”这里 这个想法很是巧妙
G:
我犯二的题 我一开始想 按照不讨厌来建边 然后最大团就是答案 但是点这么多… 这时队友说 “简单的二维不降子序列题”… 这才顿悟… 不讨厌就是S和B都大 那么不就是标准的模型了…
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[100010],mark[100010],cnt[100010];
const int inf=1e9;
struct node{
int x,y,idx;
bool operator < (const node &a) const{
return x<a.x||(x==a.x&&y>a.y);
}
}p[100010];
int main()
{
int n,t,x,y,ans;
int i;
while(scanf("%d",&n)!=EOF)
{
ans=0;
//printf("n.%d\n",n);
for(i=0;i<n;i++){
scanf("%d%d",&x,&y);
//printf("u.........%d\n",i);
p[i].x=x;
p[i].y=y;
p[i].idx=i+1;
}
sort(p,p+n);
for(i=0;i<n;i++) dp[i]=inf;
for(i=0;i<n;i++){
int tmp=lower_bound(dp,dp+n,p[i].y)-dp;
dp[tmp]=p[i].y;
mark[i]=tmp;
ans=max(ans,tmp);
}
printf("%d\n",ans+1);
int tot=0;
for(i=n-1;i>=0;i--){
if(mark[i]==ans){
cnt[tot++]=p[i].idx;
ans--;
}
}
sort(cnt,cnt+tot);
for(i=0;i<tot;i++)
{
printf("%d",cnt[i]);
if(i==tot-1) printf("\n");
else printf(" ");
}
}
return 0;
}
H:
不知道题… 队友直接就给A了… 我就贴代码吧 - -b
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long ll;
const int MAXN = 110;
#define MAX 2010
#define mod 10000
#define baselen 4
#define in(a) scanf("%d",&a)
#define out1(a) printf("%d",a)
#define out2(a) printf("%04d",a)
int a[MAXN][MAXN]; //增广矩阵
int x[MAXN]; //解集
bool free_x[MAXN]; //标记是否是不确定的变元
inline int abs(int a) {
return a > 0 ? a : -a;
}
void Debug(int equ, int var) {
int i, j;
for (i = 0; i < equ; i++) {
for (j = 0; j < var + 1; j++) {
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
//m个方程,n个变量!!
int rank(int A[MAXN][MAXN], int m, int n) //求解01模2方程的秩!!
{
int i = 0, j = 0, k, r, u;
while (i < m && j < n) //当前正在处理第i行,第j个变量!!
{
r = i;
for (k = i; k < m; k++)
if (A[k][j]) {
r = k;
break;
}
if (A[r][j]) {
if (r != i)
for (k = 0; k <= n; k++)
swap(A[r][k], A[i][k]);
for (u = i + 1; u < m; u++)
if (A[u][j])
for (k = i; k <= n; k++)
A[u][k] ^= A[i][k];
i++;
}
j++;
}
return i; //系数矩阵的秩!
}
int p[1000], flag[1000], cnt = 0;
void get_prime() {
int i, j;
for (i = 2; i < 600; i++) {
if (!flag[i])
p[cnt++] = i;
;
for (j = 0; j < cnt && p[j] * i < 600; j++) {
flag[i * p[j]] = 1;
if (i % p[j] == 0)
break;
}
}
}
int b[200];
typedef int type;
/
struct bint {
type dig[MAX], len;
bint() {
len = 0, dig[0] = 0;
}
};
//常用函数
//(1)
void add(bint a, bint b, bint& c) {
type i, carry;
for (i = carry = 0; i <= a.len || i <= b.len || carry; i++) {
if (i <= a.len)
carry += a.dig[i];
if (i <= b.len)
carry += b.dig[i];
c.dig[i] = carry % mod;
carry /= mod;
}
c.len = i - 1;
}
//(2)
void add(bint a, type b, bint& c) {
type i;
for (i = 0; i <= a.len || b; i++) {
if (i <= a.len)
b += a.dig[i];
c.dig[i] = b % mod;
b /= mod;
}
c.len = i - 1;
}
//(3)
void by(bint a, type b, bint& c) {
type i, carry;
for (i = carry = 0; i <= a.len || carry; i++) {
if (i <= a.len)
carry += b * a.dig[i];
c.dig[i] = carry % mod;
carry /= mod;
}
i--;
while (i && !c.dig[i])
i--;
c.len = i;
}
//(4)
void by(bint a, bint b, bint& c) {
type i, j, carry;
for (i = a.len + b.len + 1; i >= 0; i--)
c.dig[i] = 0;
for (i = 0; i <= a.len; i++) {
carry = 0;
for (j = 0; j <= b.len || carry; j++) {
carry += c.dig[i + j];
if (j <= b.len)
carry += a.dig[i] * b.dig[j];
c.dig[i + j] = carry % mod;
carry /= mod;
}
}
i = a.len + b.len + 1;
while (i && c.dig[i] == 0)
i--;
c.len = i;
}
//(5)
void div(bint a, type b, bint& c, type& d) {
type i;
for (i = a.len, d = 0; i >= 0; i--) {
d = d * mod + a.dig[i];
c.dig[i] = d / b;
d = d % b;
}
i = a.len;
while (i && c.dig[i] == 0)
i--;
c.len = i;
}
//(6)
bool input(bint& a) {
type i, j, w, k, p;
char data[MAX * baselen + 1];
if (scanf("%s", data) == EOF)
return false;
w = strlen(data) - 1, a.len = 0;
for (p = 0; p <= w && data[p] == '0'; p++)
;
while (1) {
i = j = 0, k = 1;
while (i < baselen && w >= p) {
j = j + (data[w--] - '0') * k;
k *= 10, i++;
}
a.dig[a.len++] = j;
if (w < p)
break;
}
a.len--;
return true;
}
//(7)
void output(bint& a) {
type i;
i = a.len - 1;
out1(a.dig[a.len]);
while (i >= 0)
out2(a.dig[i--]);
printf("\n");
}
//少用函数
//(8)
void move(bint& a) {
type carry, k, t;
k = a.len + 1, carry = 0;
while (k--) {
t = a.dig[k] & 1;
a.dig[k] = (a.dig[k] >> 1);
if (carry)
a.dig[k] += (mod >> 1);
carry = t;
}
if (a.len && a.dig[a.len] == 0)
a.len--;
}
//(9)
void sub(bint a, bint b, bint& c) {
type i, carry;
for (i = carry = 0; i <= a.len; i++) {
c.dig[i] = a.dig[i] - carry;
if (i <= b.len)
c.dig[i] -= b.dig[i];
if (c.dig[i] < 0)
carry = 1, c.dig[i] += mod;
else
carry = 0;
}
i--;
while (i && c.dig[i] == 0)
i--;
c.len = i;
}
//(10)
void sub(bint a, type b, bint& c) {
type i;
for (i = 0; i <= a.len; i++) {
c.dig[i] = a.dig[i] - b;
if (c.dig[i] < 0)
b = 1, c.dig[i] += mod;
else
b = 0;
}
i--;
while (i && c.dig[i] == 0)
i--;
c.len = i;
}
//(11)
int cmp(bint a, bint b) {
if (a.len < b.len)
return -1;
if (a.len > b.len)
return 1;
int i = a.len;
while (i && a.dig[i] == b.dig[i])
i--;
return a.dig[i] - b.dig[i];
}
//(12)
void give(bint a, bint& b) {
int i = 0;
while (i <= a.len) {
b.dig[i] = a.dig[i];
i++;
}
b.len = a.len;
}
//(13)
void give(type a, bint& b) {
b.dig[0] = a % mod;
a /= mod;
if (a > 0)
b.dig[1] = a, b.len = 1;
else
b.len = 0;
}
//(14)
void shift(bint& a, type k) {
int i;
i = a.len + k;
while (i >= k) {
a.dig[i] = a.dig[i - k];
i--;
}
while (i >= 0)
a.dig[i--] = 0;
a.len += k;
}
//(15)
void div(bint a, bint b, bint& c, bint& d) {
type x, k;
bint temp;
give(a, d);
c.len = c.dig[0] = 0;
while (cmp(d, b) > 0) {
k = d.len - b.len;
if (d.dig[d.len] > b.dig[b.len])
x = d.dig[d.len] / (b.dig[b.len] + 1);
else if (k)
k--, x = (d.dig[d.len] * mod + d.dig[d.len - 1])
/ (b.dig[b.len] + 1);
else
break;
by(b, x, temp);
shift(temp, k);
sub(d, temp, d);
give(x, temp);
shift(temp, k);
add(c, temp, c);
}
if (cmp(d, b) >= 0)
sub(d, b, d), add(c, (type) 1, c);
}
int main() {
get_prime();
//for(int i=0;i<=100;i++)printf("%d %d\n",i+1,p[i]);
int i, j, t, m;
while (~scanf("%d%d", &t, &m)) {
int xx;
memset(a, 0, sizeof(a));
for (i = 0; i < m; i++) {
scanf("%d", &xx);
for (j = 0; j < t; j++)
while (xx % p[j] == 0) {
xx /= p[j];
a[j][i] ^= 1;
}
}
//Debug(maxp+1,n);
int r = rank(a, t, m);
int y = m - r;
if (y < 64) {
ll ans = (1LL << y) - 1;
printf("%lld\n", ans);
continue;
}
bint tmp, Ans;
give(1, Ans);
while (y--) {
tmp = Ans;
by(tmp, 2, Ans);
}
tmp = Ans;
sub(tmp, 1, Ans);
output(Ans);
}
return 0;
}