問題解決のレポートの「NOI2016」美サイクル

米国の「NOI2016」サイクル

小数のため\(\ FRAC {A}、{B} \) もしそうであれば(K \)\するバイナリ数であり、繰り返さない要件を満たす必要があります。

これはスコアを繰り返さないことを確認してくださいされた最も簡単な分数である\((A、B)= 1 \)

まだ裏で起こる最初の残りを満たすための必要性を満たす、最初の余りがある\(A \ BMOD Bが\) バック(X \)\実際余りビット\(\回K ^ X \ BMOD B \)

だから我々は、満たす必要がある
[\回\当量を\
\ Bのk ^ X \ PMOD] 可解性

以降\((A、B)= 1 \) そう
[K ^ X \当量1 \
\ B \ PMOD] もし\((K、B)= 1 \) 次いで、オイラーの定理、可解性の\( X = \ varphi(X)\ )

そうでない場合に起因\(k個の\倍K ^ { X-1} -YB = 1 \) 非整数解液、無溶液ように、元の式

于是我们需要统计的即为
\ [\ sum_ {i = 1} ^ m個の\ sum_ {J = 1} ^ N [(I、K)= 1] [(I、J)= 1] \]
推式子
\ [\ {整列}始めるとの\ sum_ {i = 1} ^ m個の\ sum_ {J = 1} ^ N [(I、K)= 1] [(I、J)= 1] \\ =&\ sum_ {i = 1} ^ m個の[(I、K)= 1] \ sum_ {J = 1} ^ n個の\ sum_ {D = 1} ^ {\分(i、j)は} \ MU(D)[D |私は\ランドD | J] \\ =&\のsum_ {D = 1} ^ {\分(N、M)} \ MU(D)\ lfloor \ FRAC {n}は{D} \ rfloor \ sum_ {I = 1} ^ m個の[(I、K)= 1 \ランドD | I] \\ =&\ sum_ {D = 1} ^ {\分(n、m)はミュー\}(D)\ lfloor \ FRAC {N } {D} \ rfloor \ sum_ {i = 1} ^ {\ lfloorの\のFRAC {M} {D} \ rfloor} [(ジ、K)= 1] \\ =&\のsum_ {D = 1} ^ { MU(D)\ \分(N、M)} [(D、K)= 1] \ lfloor \ FRAC {n}は{D} \ rfloor \ sum_ {i = 1} ^ {\ lfloorの\のFRAC {M} {D} \ rfloor} [(I、K)= 1] \\ \端{整列} \]
我们知道\((A、B)=(\のBMODのB、B)\)

この質問\(K \)は、我々が前処理することができるように、小さい
\ [なる(I)= [ (I、K)= 1] \\ F(I)= \ sum_ {jが= 1} ^ IIS( J)は\]
次に、上記式は
\ [\ sum_ {D = 1 } ^ {\分(N、M)}ミュー(D)は(\ D \ BMOD K)\ lfloor \ FRAC {n}は{D } \ rfloor(\ lfloor \ FRAC
{M} {DK} \ rfloor F(K)+ F(\ lfloorの\のFRAC {M} {D} \ rfloor \ BMOD K))\] 私たちはでき\(O( K \ログK + N)\ ) の時間では、問題を解決するために、あなたが得ることができます(\ 84 \)ポイント、良い結果を

我々が設定されていることに注意してください
\ [F(N)= \
lfloor \ FRAC {n}は{K} \ rfloor F(K)+ F(N \ BMOD K)\] 元の式
\ [\ sum_ {D = 1 } ^ {\分(N、M) }ミュー(D)(D、K)= 1] \ lfloor \ FRAC {n}は{D} \ \ rfloor F(\ lfloorの\のFRAC {M} {D} \ rfloor) \]
2つの明らかに割り切れるブロックの後ろに、フロントと2つのプレフィックスを考慮して決定

セット
\ [G(N、K)
= \ sum_ {D = 1} ^ n個の\ミュー(D)(D、K)= 1] \] 式プッシュ検討
[\ {整列} Gを開始\を ( N、K)=&\のsum_ {D = 1} ^ n個の\ミュー(D)(D、K)= 1] \\ =&\のsum_ {D = 1} ^ n個の\ミュー(D)\ sum_ { P = 1} ^ {\分 (D、K)}ミュー(P)\ [P | Dの\ランドP | K] \\ =&\のsum_ {P |ミュー(P)\ K} \ sum_ {P | D} ^ n個の\ミュー(D )\\ =&\のsum_ {P | K}ミュー(P)\ \ sum_ {D = 1} ^ {\ lfloorの\のFRAC {N} {P} \ rfloor}ミュー(\ DP)\\ \ mathbb {ため\の}&\ [MU \(DP)\ない= 0] = [(D、P)= 1]、\ mathbb {そう} \\ G(N、K)=& \ sum_ {P | K} \の MU(P)\ sum_ {D = 1} ^ {\ lfloorの\のFRAC {N} {P} \ rfloor}ミュー(DP)\ [(D、P)= 1] \\ =&\ sum_ {P | K } \ミュー^ 2(P)\ sum_ {D = 1} ^ {\ lfloorの\のFRAC {N} {P} \ rfloor}ミュー(D)(D、P)\ = 1] \\ =&\のsum_ {
P | K} \ミュー^ 2(p)はG(\ lfloorの\のFRAC {N} {P} \ rfloor、P)\端\] {整列} 境界
\ [G(N 、1)= \ sum_ {D
^ n個の\ミュー(D)、G(0 = 1}、K)= 0 \] 画面の前面に教えるために、約デュ

複雑さは、本当に忘れていません...


コード:

#include <cstdio>
#include <cctype>
#include <map>
#include <algorithm>
#define ll long long
using std::min;
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
    x=0;char c=gc();
    while(!isdigit(c)) c=gc();
    while(isdigit(c)) x=x*10+c-'0',c=gc();
}
const int N=5e6+1;
int mu[N],pri[N],ispri[N],fmu[N],cnt,toki[2020],aya[2020];
void init()
{
    fmu[1]=mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!ispri[i])
        {
            pri[++cnt]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=cnt&&i*pri[j]<N;j++)
        {
            ispri[i*pri[j]]=1;
            if(i%pri[j]) mu[i*pri[j]]=-mu[i];
            else break;
        }
        fmu[i]=fmu[i-1]+mu[i];
    }
}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
std::map <std::pair<int,int>,int> saki;
int g(int x,int k)
{
    //if(x<=1) return n;
    if((k==1&&x<N)||(!x)) return fmu[x];
    std::pair<int,int> now=std::make_pair(x,k);
    if(saki[now]) return saki[now];
    int ret=0;
    if(k==1)
    {
        ret=1;
        for(int l=2,r;l<=x;l=r+1)
        {
            r=x/(x/l);
            ret-=g(x/l,k)*(r+1-l);
        }
    }
    else
    {
        for(int i=1;i*i<=k;i++)
        {
            if(k%i) continue;
            if(mu[i]) ret+=g(x/i,i);
            if(i*i!=k&&mu[k/i]) ret+=g(x/(k/i),k/i);
        }
    }
    return saki[now]=ret;
}
int n,m,k;
int F(int x){return (x/k)*toki[k]+toki[x%k];}
int main()
{
    init();
    read(n),read(m),read(k);
    for(int i=1;i<=k;i++)
        toki[i]=toki[i-1]+(gcd(k,i)==1);
    ll las=0,now,ans=0;
    for(int l=1,r;l<=min(n,m);l=r+1)
    {
        r=min(n/(n/l),m/(m/l));
        ans+=1ll*((now=g(r,k))-las)*(n/l)*F(m/l);
        las=now;
    }
    printf("%lld\n",ans);
    return 0;
}

2019年5月30日

おすすめ

転載: www.cnblogs.com/butterflydew/p/10947506.html
おすすめ