【转】【SNOI 2017】遗失的答案
Solution
https://www.luogu.com.cn/blog/MachineryCountry/solution-p5366
https://www.luogu.com.cn/blog/m-sea/solution-p5366
全集含义:整个集合里面所有质因子都有没有的数,所有质因子都有一个数存在那个质因子的指数与最小公倍数相等。
这里的对位是 \(S\)。
Code
#pragma GCC optimize(2)
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7;
int cnt, lim, n, G, l, q, pc, p[10], c[10], num[650], sum[650], s[1 << 16], f[650][1 << 16], g[650][1 << 16], h[650][1 << 16], ans[650];
vector <int> v;
int read() {
int x = 0, f = 1; char s;
while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
return x * f;
}
int inc(int x, const int y) {
x = x + y;
if(x >= mod) x -= mod;
return x;
}
int sub(int x, const int y) {
x = x - y;
if(x < 0) x += mod;
return x;
}
int qkpow(int x, int y) {
int r = 1;
while(y) {
if(y & 1) r = 1ll * r * x % mod;
x = 1ll * x * x % mod; y >>= 1;
}
return r;
}
void divide(int x) {
for(int i = 2; i * i <= x; ++ i) {
if(x % i) continue;
p[++ pc] = i;
while(x % i == 0) x /= i, ++ c[pc];
}
if(x > 1) p[++ pc] = x, ++ c[pc];
}
void FWT(int *f, const int op = 1) {
for(int i = 2; i <= lim; i <<= 1)
for(int j = 0, p = i >> 1; j < lim; j += i)
for(int k = j; k < j + p; ++ k)
if(op == 1) f[k + p] = inc(f[k + p], f[k]);
else f[k + p] = sub(f[k + p], f[k]);
}
int cal(int x) {
int r = 0, tot;
for(int i = 1; i <= pc; ++ i) {
tot = 0;
while(x % p[i] == 0) x /= p[i], ++ tot;
if(tot == 0) r |= 1 << i - 1;
if(tot == c[i]) r |= 1 << i - 1 + pc;
}
return r;
}
int main() {
int x;
n = read(), G = read(), l = read(), q = read();
if(l % G) {while(q --) puts("0"); return 0;}
l /= G, n /= G; divide(l);
for(int i = 1; i <= n && i * i <= l; ++ i) {
if(l % i) continue;
v.push_back(i);
if(i * i != l && l / i <= n) v.push_back(l / i);
}
for(int i = 0, siz = v.size(); i < siz; ++ i) ++ s[cal(v[i])];
lim = 1 << (pc << 1);
for(int i = 0; i < lim; ++ i)
if(s[i]) num[++ cnt] = i, sum[cnt] = qkpow(2, s[i]) - 1;//去掉全不选
f[0][0] = g[cnt + 1][0] = 1;
for(int i = 1; i <= cnt; ++ i)
for(int S = 0; S < lim; ++ S) {
f[i][S] = inc(f[i][S], f[i - 1][S]);
f[i][S | num[i]] = inc(f[i][S | num[i]], 1ll * sum[i] * f[i - 1][S] % mod);
}
for(int i = cnt; i; -- i)
for(int S = 0; S < lim; ++ S) {
g[i][S] = inc(g[i][S], g[i + 1][S]);
g[i][S | num[i]] = inc(g[i][S | num[i]], 1ll * sum[i] * g[i + 1][S] % mod);
}
for(int i = 0; i <= cnt; ++ i) FWT(f[i]);
for(int i = 1; i <= cnt + 1; ++ i) FWT(g[i]);
for(int i = 1; i <= cnt; ++ i)
for(int S = 0; S < lim; ++ S)
h[i][S] = 1ll * f[i - 1][S] * g[i + 1][S] % mod;
for(int i = 1; i <= cnt; ++ i) FWT(h[i], -1);
for(int i = 1; i <= cnt; ++ i) {
for(int S = 0; S < lim; ++ S)
if((S | num[i]) == lim - 1) ans[i] = inc(ans[i], h[i][S]);
ans[i] = 1ll * ans[i] * qkpow(2, s[num[i]] - 1) % mod;
}
while(q --) {
x = read();
if(x % G) {puts("0"); continue;}
x /= G;
if(l % x || x > n) {puts("0"); continue;}
printf("%d\n", ans[lower_bound(num + 1, num + cnt + 1, cal(x)) - num]);
}
return 0;
}
浙公网安备 33010602011771号