[51Nod 1224] 階乘的冪的倍數

這裏寫圖片描述

題解:注意到 f(i, k) 一定單調, 從小到大枚舉每一個 i , 分解素數可以求出此時滿足條件的最小的 N …… 看代碼把 ಥ_ಥ …… 不會證明覆雜度…. n 乘若干個 log ? hhhhhhhh

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int mo = 1e9 + 7;
const int N = 1e6 + 10;

int prime[N], minn[N], cnt;
bool vis[N];

void prepare(int n)
{
    minn[1] = 1;
    for (int i = 2; i <= n; ++i)
    {
        if (!vis[i]) prime[++cnt] = minn[i] = i;
        for (int j = 1; j <= cnt; ++j)
        {
            int to = prime[j] * i;
            if (to > n) break;
            vis[to] = 1, minn[to] = prime[j];
            if (i % prime[j] == 0) break;
        }
    }
}

int n; LL k;
LL sum, now = 1;

LL getNum(LL x, int p)
{
    LL ret = 0;
    while (x) ret += (x /= p);
    return ret;
}

LL C[N], Pow[60], Stk[60];
void addPrime(int x, LL c)
{
    C[x] += c;
    if (getNum(now, x) < C[x])
    {
        LL tmp = C[x];
        int l = -1;
        while (Stk[++l] < C[x])
        {
            Pow[l + 1] = Pow[l] * x;
            Stk[l + 1] = Stk[l] + Pow[l];
        }
        for (now = 0; l; --l) if (tmp >= Stk[l])
        {
            LL q = tmp / Stk[l];
            now += Pow[l] * q;
            tmp -= Stk[l] * q;
        }
    }
}

void insert(int x)
{
    while (x > 1)
    {
        int tmp = minn[x], cnt = 0;
        while (minn[x] == tmp) x /= tmp, cnt++;
        addPrime(tmp, k * cnt); 
    }
}

int main()
{
    scanf("%d%lld", &n, &k);
    prepare(n), Pow[0] = 1;
    for (int i = 2; i <= n; ++i)
    {
        insert(i);
        sum = (sum + now) % mo;
    }
    printf("%lld\n", sum);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章