[NOI2016] [BZOJ4652] [羅区P1587]米国(杜のティーチふるい)のサイクル

フェイス質問

https://www.luogu.com.cn/problem/P1587

問題の解決策

事前知識

すべての質問が尋ね(1 {\当量}、X \ {\}当量のN、1 {\当量} Y {\当量} M \) に形成され\({\ FRAC {X} {Y}} \) K進異なる純粋で小数点以下の桁数。(整数とみなすことができます)

被験者の解析、変換条件:純粋な循環小数と等価\((Y、K)= 1 \。) ;及び全ての重複する値(\ {\ FRAC {X} {Y}} \) 順番には、取ることができる((\ X、Y)= 1 \)代表として、あまり良好統計こと。

追求するので、同等

\ [{\和\ limits_ {Y = 1} ^ {M}} {\和\ limits_ {X = 1} ^ {N}} [(Y、K)= 1] [(X、Y)= 1] \]

\ [= {\和\ limits_ {Y = 1} ^ {M}} [(Y、K)= 1] {\和\ limits_ {X = 1} ^ {N}} {\和\ limits_ {D | X、D | Y}} {\ MU(D)} \]

\ [= {\和\ limits_ {Y = 1} ^ {M}} [(Y、K)= 1] {\和\ limits_ {D | Y} ^ {1 {\当量} D {\当量}分(N、M)}} {\ MU(D)} {\ lfloor} {\ FRAC {n}は{D}} {\ rfloor} \]

\ [= {\和\限界_ {(D、K)= 1} ^ {1 {\当量} D {\当量}分(N、M)}} {\ MU(D)} {\ lfloor} {\ FRAC {n}は{D}} {\ rfloor} {\和\ limits_ {Y '= 1} ^ {{\ lfloor} {\ FRAC {M} {D}} {\ rfloor}}} [(Y'、 K)= 1] \]

\({\ MU(D) } \) 既にブロック番号理論によって処理何か後ろ。\({\ sum_ {Y ' = 1} ^ {{\ lfloor} {\ FRAC {M} {D}} {\ rfloor}}} [(Y'、K)= 1] \) この部分、意味〜1 \({\ lfloor} {\ FRAC D {M}}}、{{\ rfloor} \)番号k素数と\(F({\ lfloor} {\ FRAC {M} {D {}} \ rfloor})\)小さなkに、我々は、前処理されてもよい\(F(1)\)\(F(K)\) 次いで(\ {\ lfloor} {\ FRAC {M} {D}} {\ rfloor} \) 残りのk及びkで割った整数倍数の後、我々はでき(O(1)\)\アドレスこの部分。

残りのものは、解決する方法である(\ {\ SUMは_ {(D、K)= 1} ^ {1 {\のLeq} D {\のLeq} R} {\ MU(D)を} \) R理論です、ブロックの右端の後。

二つの画面がDUが全て解決する教えることができるように、m個のR割り切れる特定のセットの全てにおいて見出さ又はn \(合計\ MU(R) = {\ sum_ {1 {\当量} D {\当量} R}を{} \ MU(D)} \) 問題は、今も\((D、K)= 1 \) 条件。

我々は考える\({\和_ {( D、K){\ NEQ} 1} ^ {1 {\当量} D {\当量} R} {\ MU(d)は} \) です。次に、検索するための驚き:起因する小さなkに、そう満足するよう\((D、K){\ NEQ} 1 \。)だけでなく、満たすために、({\ MU(D)\ {\ NEQ} 0} \) 実際にはない数たくさん。

\(DT(R)\)これを記述すると。上記の条件を満足する行を考えるDおよびK、K-GCD一部のみ素因数をGCD、各周波数は、1個以下にすることはできません。しかしながら、\({K \}のLeq 2000 \) その結果、4 K素因数の唯一最大。だから、これは15までGCD。その後、関係が描かれることができます:

\ [DT(N)= {\和\ limits_ {GCD}} {\} {\和\限界_ {(D、K)= 1} ^ {1 {\当量} D {\当量} {\ FRAC {K } {GCD}}}} {\ MU(D)} \]

\ [= {\和\ limits_ {GCD}} {\ MU(GCD)}(合計\ MU({\ FRAC {K} {GCD}}) - DT(\ FRAC {K} {GCD}))\]

全てDTまたは添字後に表示されるn個のすべてのDTの合計の計算の複雑さがあるので、セット内の数mで割り切れる\(O(({\ SQRT {N}} + \ SQRT {M}))w \) ここで、wは、この問題では、異なるGCDの数であり、{\}のLeq 15 \)W(\

要約すると、この質問の合計時間複雑である\(O(\ SQRT {W} + N-N- ^ {\ FRAC。3} {2} {})\)

コード

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define rg register
#define K 2000
#define T 1000000

ll n,m,k,pn;
ll pri[T+5],smu[T+5];
bool isp[T+5]; 

inline void Eular(){
    smu[1] = 1;
    for(rg ll i = 2;i <= T;i++)isp[i] = 1;
    for(rg ll i = 2;i <= T;i++){
        if(isp[i])pri[++pn] = i,smu[i] = -1;
        for(rg ll j = 1;i * pri[j] <= T;j++){
            isp[i*pri[j]] = 0;
            if(i % pri[j])smu[i*pri[j]] = -smu[i];
            else{
                smu[i*pri[j]] = 0;
                break;
            }
        }
    }
    for(rg ll i = 2;i <= T;i++)smu[i] += smu[i-1];
}

ll f[K+5]; //f[i]表示1~i中与k互质的数的个数 

inline ll gcd(ll a,ll b){
    return b ? gcd(b,a % b) : a;
}

inline ll calc(ll n){ //计算1~i中与k互质的数的个数 
    return (n / k) * f[k] + f[n%k];
}

unordered_map<ll,ll>Hash;

inline ll summu(int n){ //杜教筛 
    if(n <= T)return smu[n];
    if(Hash.count(n))return Hash[n];
    ll ans = 1;
    int L,R = 1;
    while(R < n){
        L = R + 1,R = n / (n / L);
        ans -= 1ll * (R - L + 1) * summu(n / L);
    }
    return Hash[n] = ans;
}

vector<ll>fac;
ll fn,fc[16+5]; //所有k的mu值不等于0的约数(除了1) 

inline void divide(ll n){ //分解k 
    for(rg ll i = 1;i <= pn;i++){
        if(n % pri[i] == 0){
            fac.push_back(pri[i]);
            while(n % pri[i] == 0)n /= pri[i];
        }
        if(n == 1)break;
    }
} 

unordered_map<ll,ll>Dt;

inline ll dt(int n){ //1~n中与k互质的数的\mu值之和 
    if(!n)return 0; 
    if(Dt.count(n))return Dt[n];
    ll ans = 0;
    for(rg ll i = 1;i <= fn;i++)ans += (smu[fc[i]] - smu[fc[i]-1]) * (summu(n/fc[i]) - dt(n/fc[i]));
    return Dt[n] = ans;
}

int main(){
    cin >> n >> m >> k;
    Eular();
    divide(k);
    for(rg ll mask = 1;mask < 1ll << fac.size();mask++){
        ll cur = 1;
        for(rg ll i = 0;i < fac.size();i++)
            if((bool)(mask & (1ll << i)))cur *= fac[i];
        fc[++fn] = cur;
    }
    for(rg ll i = 1;i <= k;i++)f[i] = f[i-1] + (gcd(i,k) == 1);
    ll ans = 0;
    int L,R = 0,limit = min(n,m);
    while(R < limit){
        L = R + 1,R = min(n / (n/L),m / (m/L));
        ans += ((summu(R)-dt(R)) - (summu(L-1)-dt(L-1))) * (n / L) * calc(m / L);
    } 
    cout << ans << endl;
    return 0;
}

おすすめ

転載: www.cnblogs.com/xh092113/p/12301812.html