1. 程式人生 > >【GDOI2016模擬3.16】冪

【GDOI2016模擬3.16】冪

Description:

這裡寫圖片描述
這裡寫圖片描述

題解:

x=piqid=gcd(qi)

d>1,我們先不考慮它。

d=1x>n,則xy一定不會與其他有重的,貢獻為B。

d=1x<=n,設L=logxn,顯然對於L一樣的貢獻是一樣。

由於(xy)z=xyz,所以問題轉換為x[1..L]y[1..B],xy有多少不同取值。

劃分一下範圍變成問[1..LB]有多少數滿足有至少一組xy=它,這個可以想到用容斥原理做,大概要維護lcm和最小的選了的數。

但是L最大是29,會超時。

注意lcm(129)的約數個數不多,也就是說可能的lcm個數不多,於是按DAG順序dp,複雜度就降了下來。

還有一種想法是分塊考慮。

列舉i,當前塊是((i1)B,iB]

顯然只有x[i..L]的才會對它們產生影響,若一數是x[i..L]的倍數,則這個數可以。

當時複雜度好像還是229,若[i..L]中有兩數d1、d2,滿足d1|d2,顯然只用保留d1,最大的話還剩15個數。

Code:

#include<cstdio>
#define ll long long #define fo(i, x, y) for(int i = x; i <= y; i ++) using namespace std; const int M = 100000; int bz[M + 5], p[M + 5], u[M + 5]; int n, m, s[100]; ll ans, sum; int gcd(ll x, ll y) {return !y ? x : gcd(y, x % y);} void Shai() { fo(i, 2, M) { if(!bz[i]) p[++ p[0]] = i, u[i] = i; fo(j, 1
, p[0]) { int k = i * p[j]; if(k > M) break; bz[k] = 1; u[k] = p[j]; if(i % p[j] == 0) break; } } u[1] = 1; } void dg(int x, int y, int z) { if(z == 1) return; ans --; fo(j, y, p[0]) { int k = 1; for(ll u = (ll) x * p[j]; u <= n; u *= p[j], k ++) dg(u, j + 1, gcd(k, z)); if(k == 1) return; } } int t, w[M], bx[M]; void dfs(int x, ll lcm, int fu) { if(x > w[0]) { if(lcm == 1 && fu == -1) return; sum += fu * ((ll) t * m / lcm - (ll) (t - 1) * m / lcm); return; } dfs(x + 1, lcm, fu); dfs(x + 1, lcm * w[x] / gcd(lcm, w[x]), -fu); } int main() { Shai(); scanf("%d %d", &n, &m); ans = n; dg(1, 1, 0); ans = ans * m; ans ++; fo(i, 2, M) if(i * i <= n) { int x = i, gd = 0; while(x > 1) { int y = u[x], z = 0; while(x % y == 0) x /= y, z ++; gd = gcd(gd, z); } x = 1; int y = 0; while((ll) x * i <= n) x *= i, y ++; if(gd == 1) { ans -= m; s[y] ++; } } else break; fo(i, 2, 29) if(s[i]) { sum = 0; fo(j, 1, i) { t = j; w[0] = 0; fo(k, j, i) bx[k] = 0; fo(k, j, i) if(!bx[k]) { w[++ w[0]] = k; fo(o, 1, i / k) bx[o * k] = 1; } dfs(1, 1, -1); } ans += sum * s[i]; } printf("%lld\n", ans); }