当前位置: 首页 > 工具软件 > Scut > 使用案例 >

SCUT - 11 - 被钦定的选手 - 质因数分解

严瑞
2023-12-01

https://scut.online/p/11

T了好多次,还想用mutimap暴力分解每个数的质因数。后来记录每个数的最小质因子过了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, MOD;

const int SIZE = 1e6, SIZEP = 8e4;

int p2[SIZE + 5], p5[SIZE + 5];
int p[SIZEP + 5], ptop;
int minp[SIZE + 5];

void init() {
    for(int i = 2; i <= SIZE; i *= 2) {
        for(int j = i; j <= SIZE; j += i)
            p2[j] ++;
    }
    for(int i = 5; i <= SIZE; i *= 5) {
        for(int j = i; j <= SIZE; j += i)
            p5[j] ++;
    }
    minp[1] = 1;
    for(int i = 2; i <= SIZE; i++) {
        if(!minp[i]) {
            p[++ptop] = i;
            minp[i] = ptop;
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= SIZE; j++) {
            minp[t] = j;
            if(i % p[j] == 0)
                break;
        }
    }
    //cout<<ptop<<endl;
}


int cntp[SIZEP + 5];

void cnt(int n, int d) {
    while(n != 1) {
        cntp[minp[n]] += d;
        n /= p[minp[n]];
    }
}

int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

int calc() {
    memset(cntp, 0, sizeof(cntp));
    m = min(n - m, m);
    for(int i = 1; i <= m; ++i) {
        cnt(n - i + 1, 1);
        cnt(i, -1);
    }
    int min10 = min(cntp[1], cntp[3]);
    cntp[1] -= min10, cntp[3] -= min10;
    printf("%d ", min10);
    ll ans = 1;
    for(int i = 1; i <= ptop; ++i)
        ans = ans * (qpow(p[i], cntp[i])) % MOD;
    return ans % MOD;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    init();
    while(~scanf("%d%d%d", &n, &m, &MOD))
        printf("%d\n", calc());
}

事实上,这个是个阶乘(DQ的方法),那么阶乘以内的各个质因子的贡献是可以算出来的,具体而言,2会贡献n/2个2,4再贡献n/4个2,8再贡献n/8个2。

用上面的方法,每个质因数会贡献一个log,一共是80000logn,而我的方法则是1000000logn,而且我对p2和p5的预处理并不是线性的(后面发现这两个白处理)。

二分memset,丧心病狂。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, MOD;

const int SIZE = 1e6, SIZEP = 8e4;
int p[SIZEP + 5], ptop;
int minp[SIZE + 5];

void init() {
    minp[1] = 1;
    for(int i = 2; i <= SIZE; i++) {
        if(!minp[i]) {
            p[++ptop] = i;
            minp[i] = ptop;
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= SIZE; j++) {
            minp[t] = j;
            if(i % p[j] == 0)
                break;
        }
    }
    //cout<<ptop<<endl;
}

int maxptop;
int cntp[SIZEP + 5];

void cnt(int n, int d) {
    /*while(n != 1) {
        cntp[minp[n]] += d;
        n /= p[minp[n]];
    }*/
    for(int i=1;i<=maxptop;++i){
        int tmp=n;
        while(tmp/=p[i]){
            cntp[i]+=tmp*d;
        }
    }
}

int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

int calc() {
    maxptop=min(int(lower_bound(p+1,p+1+ptop,n)-p),ptop);
    memset(cntp, 0, sizeof(cntp[0])*(maxptop+1));
    /*m = min(n - m, m);
    for(int i = 1; i <= m; ++i) {
        cnt(n - i + 1, 1);
        cnt(i, -1);
    }*/
    cnt(n,1);
    cnt(m,-1);
    cnt(n-m,-1);
    int min10 = min(cntp[1], cntp[3]);
    cntp[1] -= min10, cntp[3] -= min10;
    printf("%d ", min10);
    ll ans = 1;
    for(int i = 1; i <= maxptop; ++i){
        if(cntp[i])
            ans = ans * (qpow(p[i], cntp[i])) % MOD;
    }
    return ans % MOD;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    init();
    while(~scanf("%d%d%d", &n, &m, &MOD))
        printf("%d\n", calc());
}

转载于:https://www.cnblogs.com/Yinku/p/11297087.html

 类似资料: