【GDOI2016模擬3.16】冪
阿新 • • 發佈:2019-02-15
Description:
題解:
設,
若,我們先不考慮它。
若,則一定不會與其他有重的,貢獻為B。
若,設,顯然對於L一樣的貢獻是一樣。
由於,所以問題轉換為,xy有多少不同取值。
劃分一下範圍變成問有多少數滿足有至少一組xy=它,這個可以想到用容斥原理做,大概要維護lcm和最小的選了的數。
但是L最大是,會超時。
注意的約數個數不多,也就是說可能的lcm個數不多,於是按DAG順序dp,複雜度就降了下來。
還有一種想法是分塊考慮。
列舉i,當前塊是
顯然只有的才會對它們產生影響,若一數是的倍數,則這個數可以。
當時複雜度好像還是,若中有兩數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);
}