列表

详情


NC25114. 小w的互质集

描述

doge有一个集合A,A中有n个互不相同的元素且每个元素均为2到1000范围内的正整数。

他要求小w从A中选出一个集合B,使得,a和b不是同一个元素。

也就是说要求小w选出A的一个子集B,B中元素两两互质。

集合B可以为空集,我们认为空集也是一个符合条件的互质集。

本来doge想让小w回答最多能选出多少种不同的B集合。

但是doge觉得这个问题可能太简单了,他就想办法刁难小w,于是他说:如果我的A集合是不断变化的,你还能求出互质集的数量么?

doge说1的时候,表示他现在要将一个数字x加入到集合A当中,数字x的范围也在2到1000,并且在操作前,A集合没有x。
当doge说2的时候,表示他现在要将一个数字x从集合A当中删除,数字x的范围也在2到1000,并且在操作前A集合中一定存在x。
当doge说3的时候,表示问小w最多能选出多少种不同的B集合,请你输出答案对取模后的结果。

当且仅当两个集合中含有至少一个元素不同时,我们认为它们是不一样的集合。
也就是说对于两个集合A,B

当且仅当或者时,

输入描述

第一行是一个正整数n。且当n=0时,表示A集合为空集。

若n不为0,则接下来一行n个互不相同的正整数ai

接下来输入一个正整数m,表示操作的数量。

接下来m行,每行先输入一个正整数Q,表示操作类型。

如果Q=1,则还需输入一个正整数x,表示需要添加的数字。

如果Q=2,则还需输入一个正整数x,表示删除的数字。
如果Q=3,请你帮助小w求出当前能从A中选出多少个符合条件的B集合,并输出答案对取模后的结果。
输入数据保证至少进行了一次查询操作

输出描述

对于每一个Q=3,输出答案对取模后的结果。

示例1

输入:

0
13
3
1 2
3
1 3
3
1 6
3
1 4
3
2 6
3
1 8
3

输出:

1
2
4
5
7
6
8

说明:

一开始A集合为,此时查询答案为1,即B集合也是

加入2后,A集合为{2},答案为2,B可为、{2}

加入3后,A集合为{2,3},答案为4,B可为、{2}、{3}、{2,3}

加入6后,A集合为{2,3,6},答案为5,B集合可为、{2}、{3}、{6}、{2,3}

加入4后,A集合为{2,3,4,6}答案为7,B集合可为、{2}、{3}、{4}、{6}、{2,3}、{3,4}

移除6后,A集合为{2,3,4},答案为6,B集合可为、{2}、{3}、{4}、{2,3}、{3,4}

加入8后,A集合为{2,3,4,8},答案为8,B集合可为、{2}、{3}、{4}、{8}、{2,3}、{3,4}、{3,8}

示例2

输入:

2
431 862
3
3
1 2
3

输出:

3
5

说明:

431是一个质数
862=431*2
所以一上来答案为3,B可为、{431}、{862}
加入2后答案为5,B可为、{2}、{431}、{862}、{431,2}

示例3

输入:

10
2 3 5 7 11 13 17 19 23 29
1
3

输出:

1024

说明:

10个质数都可以选或者不选,最终答案为2^{10}=1024

示例4

输入:

9
2 4 8 16 32 64 128 256 512
1
3

输出:

10

说明:

9个数均为2的幂,算上不选一共10种合法的情况。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 72ms, 内存消耗: 592K, 提交时间: 2019-06-21 22:31:06

#include <bits/stdc++.h>
using namespace std;

const int P = 1000000007;
int n, m, f[1 << 11], g[1 << 11], p[1005], tot;
bool np[1005];
vector<int> gr[2005];

pair<int, int> divide(int x) {
	int tmp = x, s = 0;
	for (int i = 0; i < tot; ++i)
		if (x % p[i] == 0) {
			s |= 1 << i;
			while (x % p[i] == 0) x /= p[i];
		}
	return make_pair(s, x == 1 ? 1000 + tmp : x);
}
void add(const vector<int> &v) {
	for (int i = 0; i < 1 << tot; ++i)
		if (f[i]) {
			g[i] = (g[i] + f[i]) % P;
			for (int s : v)
				if ((s & i) == 0)
					g[i | s] = (g[i | s] + f[i]) % P;
		}
	copy(g, g + (1 << tot), f);
	fill(g, g + (1 << tot), 0);
}
void del(const vector<int> &v) {
	bool flag = count(v.begin(), v.end(), 0);
	for (int i = 0; i < 1 << tot; ++i) {
		g[i] = f[i];
		for (int s : v)
			if (s && (s & i) == s)
				g[i] = (g[i] - g[i - s]) % P;
		if (flag)
			g[i] = (P + 1LL) / 2 * g[i] % P;
	}
	copy(g, g + (1 << tot), f);
	fill(g, g + (1 << tot), 0);
}
void add(const pair<int, int> &p) {
	del(gr[p.second]);
	gr[p.second].push_back(p.first);
	add(gr[p.second]);
}
void del(const pair<int, int> &p) {
	del(gr[p.second]);
	vector<int> tmp;
	bool first = true;
	for (int x : gr[p.second]) {
		if (x != p.first) tmp.push_back(x);
		else if (first) first = false;
		else tmp.push_back(x);
	}
	gr[p.second] = tmp;
	add(gr[p.second]);
}

int main() {
	for (int i = 2; i * i <= 1000; ++i) {
		if (!np[i]) p[tot++] = i;
		for (int j = 0; j < tot && p[j] * i <= 1000; ++j) {
			np[p[j] * i] = true;
			if (i % p[j] == 0) break;
		}
	}
	f[0] = 1;
	scanf("%d", &n);
	for (int i = 1, x; i <= n; ++i)
		scanf("%d", &x), add(divide(x));
	scanf("%d", &m);
	for (int op, x; m--;) {
		scanf("%d", &op);
		if (op == 1) {
			scanf("%d", &x), add(divide(x));
		}
		if (op == 2) {
			scanf("%d", &x), del(divide(x));
		}
		if (op == 3) {
			int ans = 0;
			for (int i = 0; i < 1 << tot; ++i)
				ans = (ans + f[i]) % P;
			printf("%d\n", (ans + P) % P);
		}
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 121ms, 内存消耗: 632K, 提交时间: 2019-06-22 08:15:22

#include<bits/stdc++.h>

using namespace std;

const int N = 1234, mod = 1e9 + 7, prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};

void add(int& x, int y) {
  x += y;
  if (x >= mod) {
    x -= mod;
  }
}

void sub(int& x, int y) {
  x -= y;
  if (x < 0) {
    x += mod;
  }
}

int n, m, dp[1 << 11];
multiset<int> sets[N];

pair<int, int> divide(int x) {
  int y = x, s = 0;
  for (int i = 0; i < 11; ++i) {
    if (y % prime[i] == 0) {
      s |= 1 << i;
      while (y % prime[i] == 0) {
        y /= prime[i];
      }
    }
  }
  return make_pair(y == 1 ? x : y, s);
}

void add(multiset<int> sets) {
  for (int i = (1 << 11) - 1; ~i; --i) {
    bool zero = false;
    for (auto s : sets) {
      if (s && !(s & i)) {
        add(dp[s | i], dp[i]);
      }
      if (!s) {
        zero = true;
      }
    }
    if (zero) {
      dp[i] = (dp[i] << 1) % mod;
    }
  }
}

void sub(multiset<int> sets) {
  for (int i = 0; i < 1 << 11; ++i) {
    for (auto s : sets) {
      if (s && !(s & i)) {
        sub(dp[s | i], dp[i]);
      }
      if (!s) {
        dp[i] = (long long) dp[i] * (mod + 1 >> 1) % mod;
      }
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n;
  dp[0] = 1;
  for (int i = 1, x; i <= n; ++i) {
    cin >> x;
    pair<int, int> foo = divide(x);
    sub(sets[foo.first]);
    sets[foo.first].insert(foo.second);
    add(sets[foo.first]);
  }
  cin >> m;
  while (m--) {
    int op, x;
    cin >> op;
    if (op == 1 || op == 2) {
      cin >> x;
      pair<int, int> foo = divide(x);
      sub(sets[foo.first]);
      if (op == 1) {
        sets[foo.first].insert(foo.second);
      } else {
        sets[foo.first].erase(sets[foo.first].find(foo.second));
      }
      add(sets[foo.first]);
    } else {
      int answer = 0;
      for (int i = 0; i < 1 << 11; ++i) {
        add(answer, dp[i]);
      }
      cout << answer << '\n';
    }
  }
  return 0;
}

上一题