集合中的质数
题意:给出一个集合和一个数m。 集合里面有n个质数。 请你求出从 1 到 m 的所有数中,至少能被集合中的一个数整除的数的个数。
题解:
容斥原理。
先计算 m个数能把集合所有能整除的个数, 但是这样会重复计算, 比如 2, 3, 5 然后 30 即是 2的倍数又是 3的倍数又是5的倍数, 也就是第一次被计算三次, 然后枚举两个数的时候再减去, 枚举三个数的时候再加上, 奇数加
偶数减。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m, a[30], ans = 0;
void dfs(int p, int ct, ll sum) {
if (sum > m) return;
if (ct && ct % 2 == 0) {
ans -= (m / sum);
} else if (ct) {
ans += (m / sum);
}
if (p > n) return;
for (int i = p; i <= n; i++) {
dfs(i + 1, ct + 1, sum * a[i]);
}
}
int main() {
scanf("%lld %lld", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
sort(a + 1, a + n + 1);
n = unique(a + 1, a + n + 1) - a - 1;
dfs(1, 0, 1);
cout << ans << endl;
}
**题意:**给一个长为 n 的只含小写字母的字符串 每次查询一个区间 [l,r] 内,有多少子区间可以重排为一个回文串
题解: 把26个字母看成 26位0 ,1 如果两个数一样那么就会异或成0, 最后也就转换成 区间异或是否为0, 或者2的整数次幂(一个奇数), 直接用莫队算答案。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int vis[N * 100], a[N], n, m, sum[N];
int cnt[N][30], ans[N], res;
int fn[30];
char s[N];
vector<int> g;
int get_id(int x) {
return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
}
struct query{
int l, r, id;
}q[N];
int block[N];
bool cmp(query x, query y) {
if (block[x.l] == block[y.l]) {
return x.r < y.r;
}
return x.l < y.l;
}
void add(int pos) {
res += vis[sum[pos]];
for (int i = 0; i < 26; i++) {
if (cnt[pos][i] == -1) continue;
res += vis[cnt[pos][i]];
}
vis[sum[pos]]++;
}
void del(int pos) {
vis[sum[pos]]--;
res -= vis[sum[pos]];
for (int i = 0; i < 26; i++) {
if (cnt[pos][i] == -1) continue;
res -= vis[cnt[pos][i]];
}
}
int main() {
fn[0] = 1;
for (int i = 1; i <= 28; i++) {
fn[i] = fn[i - 1] * 2;
}
scanf("%d %d", &n, &m);
int b = sqrt(n);
scanf("%s", (s + 1));
for (int i = 1; i <= n; i++) {
int x = s[i] - 'a';
a[i] = (1 << x);
block[i] = i / b;
}
for (int i = 1; i <= n; i++) {
a[i] = a[i - 1] ^ a[i];
g.push_back(a[i]);
}
g.push_back(0);
sort(g.begin(), g.end());
g.erase(unique(g.begin(), g.end()), g.end());
for (int i = 0; i <= n; i++) {
for (int j = 0; j < 26; j++) {
int x = a[i] ^ fn[j];
int pos = get_id(x);
if (g[pos - 1] != x) {
cnt[i][j] = -1;
} else {
cnt[i][j] = pos;
}
}
}
for (int i = 0; i <= n; i++) {
sum[i] = get_id(a[i]);
}
for (int i = 1; i <= m; i++) {
scanf("%d %d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort(q + 1, q + m + 1, cmp);
int l = 1, r = 0;
vis[get_id(0)] = 1;
for (int i = 1; i <= m; i++) {
while (l < q[i].l) {
del(l - 1);
l++;
}
while (l > q[i].l) {
--l;
add(l - 1);
}
while (r < q[i].r) {
add(++r);
}
while (r > q[i].r) {
del(r--);
}
ans[q[i].id] = res;
}
for (int i = 1; i <= m; i++) {
printf("%d\n", ans[i]);
}
}