【GDOI2019模拟2019.2.23】签到

题目:

【GDOI2019模拟2019.2.23】签到_第1张图片
【GDOI2019模拟2019.2.23】签到_第2张图片

题解:

设是a[i]的倍数的限制为a,是b的倍数限制为b,f=1的限制为c。

相当于求:
a|b|c
=a+b+c-a&b-a&c-b&c+a&b&c

发现我们求a并不好求,考虑把所有的a改成!a

=(n-!a)+b+c-(b-!a&b)-(c-!a&c)-(b&c)+(b&c-!a&b&c)
=n-!a+!a&b+!a&c-!a&b&c

由于a[i]都是质数,所以可以看做一个积性函数, f ( p q ) = [ p ∉ a ] f(p^q)=[p∉a] f(pq)=[p/a],然后可以min_25筛。
!a&b同理。

!a&c也是差不多的。

!a&b&c的话,如果f(b)=0,要把b补成合法的,然后也是差不多的。

代码较繁琐。

Code:

#include
#include
#include
#include
#define db double
#define pp printf
#define ll long long
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
using namespace std;

const int N = 2e5 + 5;

ll n, b, a[N];
int a0, r[61];
int f[N * 10], bz[N * 10];
ll u[20]; int v[20], u0;
int p[N];
ll g[N], h[N], w[N], sp[N];
int i1[N], i2[N];
ll ans; int m, sqr;
int t[N], c[N];

void sieve(int n) {
	fo(i, 1, n) bz[i] = 0; p[0] = 0;
    fo(i, 2, n) {
        if(!bz[i]) {
			p[++ p[0]] = i;
			sp[p[0]] = sp[p[0] - 1] + !t[i];
		}
        for(int j = 1; i * p[j] <= n; j ++) {
            bz[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

ll dg(ll x, int y) {
    if(x <= 1 || p[y] > x) return 0;
    int k = x <= sqr ? i1[x] : i2[n / x];
    ll s = g[k] - sp[y - 1];
    for(int i = y; i <= p[0] && (ll) p[i] * p[i] <= x; i ++) {
        ll p1 = p[i], p2 = (ll) p[i] * p[i]; 
        if(!t[p1])
        	for(int e = 1; p2 <= x; e ++, p1 = p2, p2 *= p[i])
            	s = s + dg(x / p1, i + 1) + 1;
    }
    return s;
}

ll dd(ll x, int y) {
    if(x <= 1 || p[y] > x) return 0;
    int k = x <= sqr ? i1[x] : i2[n / x];
    ll s = h[k] - (r[1] ? sp[y - 1] : 0);
    for(int i = y; i <= p[0] && (ll) p[i] * p[i] <= x; i ++) {
        ll p1 = p[i], p2 = (ll) p[i] * p[i]; 
        if(!t[p1])
        	for(int e = 1; p2 <= x; e ++, p1 = p2, p2 *= p[i])
            	s = s + dd(x / p1, i + 1) * r[e] + r[e + 1];
    }
    return s;
}

void g1(ll n) {
	int m = 0;
    sqr = sqrt(n); sieve(sqr);
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i); w[++ m] = n / i;
        if(w[m] <= sqr) i1[w[m]] = m; else i2[n / w[m]] = m;
        g[m] = w[m] - 1;
    }
    fo(j, 1, p[0]) for(int i = 1; i <= m && (ll) p[j] * p[j] <= w[i]; i ++) {
        int k = (w[i] / p[j] <= sqr) ? i1[w[i] / p[j]] : i2[n / (w[i] / p[j])];
        g[i] = g[i] - (g[k] - (j - 1));
    }
    int x = a0;
    fo(i, 1, m) {
		while(a[x] > w[i] && x > 0) x --;
		g[i] -= x;
		if(r[1]) h[i] = g[i]; else h[i] = 0;
	}
	ans += n - (dg(n, 1) + 1);
	ans += dd(n, 1) + 1;
}

int ky = 1;

void g3(ll n) {
	int m = 0;
    sqr = sqrt(n); sieve(sqr);
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i); w[++ m] = n / i;
        if(w[m] <= sqr) i1[w[m]] = m; else i2[n / w[m]] = m;
        g[m] = w[m] - 1;
    }
    fo(j, 1, p[0]) for(int i = 1; i <= m && (ll) p[j] * p[j] <= w[i]; i ++) {
        int k = (w[i] / p[j] <= sqr) ? i1[w[i] / p[j]] : i2[n / (w[i] / p[j])];
        g[i] = g[i] - (g[k] - (j - 1));
    }
    int x = a0;
    fo(i, 1, m) {
		while(a[x] > w[i] && x > 0) x --;
		g[i] -= x;
	}
	ans += dg(n, 1) + 1;
}

void sieve2(int n) {
	fo(i, 1, n) bz[i] = 0; p[0] = 0;
    fo(i, 2, n) {
        if(!bz[i]) {
			p[++ p[0]] = i;
			sp[p[0]] = sp[p[0] - 1] + (c[i] ? r[1 + c[i]] : (t[i] ? 0 : r[1]));
		}
        for(int j = 1; i * p[j] <= n; j ++) {
            bz[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

ll dg2(ll x, int y) {
    if(x <= 1 || p[y] > x) return 0;
    int k = x <= sqr ? i1[x] : i2[n / x];
    ll s = g[k] - sp[y - 1];
    for(int i = y; i <= p[0] && (ll) p[i] * p[i] <= x; i ++) {
    	if(t[p[i]]) continue;
        ll p1 = p[i], p2 = (ll) p[i] * p[i];
        int e = 1; if(c[p1]) e += c[p1];
        for(; p2 <= x; e ++, p1 = p2, p2 *= p[i])
            s = s + (ll) dg2(x / p1, i + 1) * r[e] + r[e + 1];
    }
    return s;
}

void g2(ll n) {
	int m = 0;
    sqr = sqrt(n); sieve2(sqr);
    for(ll i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i); w[++ m] = n / i;
        if(w[m] <= sqr) i1[w[m]] = m; else i2[n / w[m]] = m;
        g[m] = w[m] - 1;
    }
    fo(j, 1, p[0]) for(int i = 1; i <= m && (ll) p[j] * p[j] <= w[i]; i ++) {
        int k = (w[i] / p[j] <= sqr) ? i1[w[i] / p[j]] : i2[n / (w[i] / p[j])];
        g[i] = (g[i] - g[k] + (j - 1));
    }
    int x = a0;
    fo(i, 1, m) {
		while(a[x] > w[i] && x > 0) x --;
		if(!r[1]) g[i] = 0;
		fo(j, 1, u0) if(u[j] <= w[i])
			g[i] += r[v[j] + 1] - r[1];
		g[i] -= x * r[1];
	}
    ans -= dg2(n, 1) + 1;
}

ll n0;

int main() {
	freopen("qiandao.in", "r", stdin);
	freopen("qiandao.out", "w", stdout);
	scanf("%lld %d %lld", &n, &a0, &b);
	fo(i, 1, a0) scanf("%lld", &a[i]);
	fo(i, 1, 60) scanf("%d", &r[i]);
	sort(a + 1, a + a0 + 1); a0 = unique(a + 1, a + a0 + 1) - (a + 1);
	fo(i, 1, a0) if(a[i] <= 1e5) t[a[i]] = 1;
	g1(n); n0 = n;
	fo(i, 1, a0) if(b % a[i] == 0) ky = 0;
	if(ky && n >= b) {
		n /= b;
		g3(n);
		n = n0;
		{
			ll x = b;
			fo(i, 2, 2e5) if(x % i == 0) {
				u[++ u0] = i;
				while(x % i == 0) x /= i, v[u0] ++;
			}
			if(x > 1) u[++ u0] = x, v[u0] = 1;
		}
		fo(i, 1, u0) if(!r[v[i]]) {
			while(!r[v[i]] && b <= n) v[i] ++, b *= u[i];
		}
		fo(i, 1, u0) if(u[i] <= 1e5) c[u[i]] = v[i];
		if(n >= b) {
			n /= b, g2(n);
		}
	}
	pp("%lld", n0 - ans);
}

你可能感兴趣的:(筛,容斥原理)