Duchi Screening Study Summary

Source: Internet
Author: User
Tags greatest common divisor

Looked at the Tang teacher's blog, Tiger did a few questions, feel the Duchi sieve some feel

But a little bit of difficulty in the topic or do not come out, the holiday time to fight for a drop (digging pit ing)

After this article, I'm going to have to go back to the upd after I've dropped those questions.

Because lazy to write how to write the formula with the editor, so the formula is ready to copy the Tang teacher directly

First, the integrable function and the fully integrable function are not much more.

Enumerate the common integrand functions:

1, about several number functions and several numbers and functions

2. Euler function phi

3. Möbius function mu

4, meta function e where E (n) =[n==1]

5. Identity function I where I (n) =1

6, Unit function ID where ID (n) =n

About the Dirichlet convolution

Defined:

We simply remember it as f*g.

Note that the Dirichlet convolution satisfies the commutative law, the binding law, and for the addition satisfies the allocation rate

Two very obvious things are: 1, f*e=e*f=f

2, set h=f*g, if f and g is an integrable function, then h is an integrable function

Some properties of the integrable function:

1.

2, E=mu*i

3, Id=phi*i

Then we can get some very interesting conclusions from the second nature:

Set the existence function G=f*i (by F for G)

Then we can get g*mu=f*i*mu.

And then simplify to get F=g*mu (by G for f)

Mr. Tang's blog also gave some more interesting examples

All right, we're done with the front-end skills.

The Duchi sieve can be expressed in the following form:

Ask F (n) =sigma (f (i))

Presence g=f*i, definition g (n) =simga (g (I))

can get f (n) =g (n)-sigma (f (n/i)) (Here I starting from 2)

If G (n) can be solved within a certain time (not necessarily requiring O (1))

Then we can do it. O (n^ (3/4)) solution f (N)

If we add some preprocessing we can do O (n^ (2/3)) solution f (N)

Here are a few examples of why this is the case:

1. Seek Sigma (Phi (i))

As we know Id=phi*i

And the prefix of the ID and the calculation of the O (1) can be

So we can do the following derivation

Yes, that's right, after the push is over the form we mentioned above, so as to prove the correctness of the above form can be used in this way of deduction

Analysis of time complexity:

This conclusion is very magical, because it seems that the complexity is like sqrt (n) *sqrt (n) =n, if you are interested, you can simplify your own, the complexity of time is really the above said

2. Seek Sigma (Mu (i))

With the above experience, we know E=mu*i

Then we can write it straight.

So that we can make the wit.

Tang Teacher's blog has a topic, but the formula is too long, will not say

With some of the things we learned above, we can brush some water problems.

(It feels good to understand and learn)

The sum of the 51Nod functions of the MO

Just apply the formula above, but there are a few things you should pay attention to in real writing.

Due to the time complexity of the Duchi sieve, the given n is usually more than the int range, which requires us to be careful with arithmetic overflow in the calculation process.

2nd, the pretreatment of how much more appropriate, their own hands-on experiment, Tang teacher said good, probably pretreatment n^ (2/3) More excellent

The 3rd is in the process of writing to each recursive calculation of the function to be stored in a hash table to achieve memory, or time complexity is difficult to guarantee

#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include < cstring>using namespace Std;const int mod=1333331;typedef long long LL; LL A, B; LL mu[5000010];int p[500010],cnt=0;bool vis[5000010];struct hashmap{int h[mod+10],cnt;int next[100010]; ll st[100010],s[100010];void push (ll K,ll v) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return;} ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=k;st[cnt]=v;} ll ask (ll k) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return st[i];} return-1;}} H;void Get_prime () {mu[1]=1;for (int i=2;i<=5000000;++i) {if (!vis[i]) {p[++cnt]=i;mu[i]=-1;} for (int j=1;j<=cnt;++j) {if (1ll*p[j]*i>5000000) Break;int ip=i*p[j];vis[ip]=true;if (i%p[j]==0) break;mu[ip]=- Mu[i];}} for (int i=2;i<=5000000;++i) mu[i]+=mu[i-1];} ll Mu_sum (ll N) {if (n<=5000000) return mu[n]; LL tmp=h.ask (n); if (tmp!=-1) return tmp; ll La,a=1;for (ll i=2;i<=n;i=la+1) {ll now=n/i;la=n/now; a=a-(la-i+1) *mu_sum (n/i);} H.push (n,a); return A;} int main() {scanf ("%lld%lld", &a,&b); Get_prime ();p rintf ("%lld\n", Mu_sum (b)-mu_sum (A-1)); return 0;}

The sum of 51Nod Euler functions

Just write it straight.

#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include < cstring>using namespace Std;const int mod=1333331;typedef long long LL; LL A, B; LL mu[5000010];int p[500010],cnt=0;bool vis[5000010];struct hashmap{int h[mod+10],cnt;int next[100010]; ll st[100010],s[100010];void push (ll K,ll v) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return;} ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=k;st[cnt]=v;} ll ask (ll k) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return st[i];} return-1;}} H;void Get_prime () {mu[1]=1;for (int i=2;i<=5000000;++i) {if (!vis[i]) {p[++cnt]=i;mu[i]=-1;} for (int j=1;j<=cnt;++j) {if (1ll*p[j]*i>5000000) Break;int ip=i*p[j];vis[ip]=true;if (i%p[j]==0) break;mu[ip]=- Mu[i];}} for (int i=2;i<=5000000;++i) mu[i]+=mu[i-1];} ll Mu_sum (ll N) {if (n<=5000000) return mu[n]; LL tmp=h.ask (n); if (tmp!=-1) return tmp; ll La,a=1;for (ll i=2;i<=n;i=la+1) {ll now=n/i;la=n/now; a=a-(la-i+1) *mu_sum (n/i);} H.push (n,a); return A;} int main() {scanf ("%lld%lld", &a,&b); Get_prime ();p rintf ("%lld\n", Mu_sum (b)-mu_sum (A-1)); return 0;}

Bzoj 3944 Sum

Mixed version of the above two topics, the only pit point is if you want to read in int, there will be a risk of explosion when i=la+1

#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include < Cstdlib>using namespace Std; typedef long LONG Ll;const int mod=1333331;int t;int p[500010],cnt=0;bool vis[2000010]; LL mu[2000010],phi[2000010];    LL n;struct hashmap{int h[mod+10],cnt;    int next[3000010];    LL s[3000010],m[3000010],p[3000010];        void push (LL k,ll V1,LL v2) {int key=k%mod;        if (key<0) Key+=mod;        for (int i=h[key];i;i=next[i]) {if (s[i]==k) return;        } ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=k; M[CNT]=V1;    P[cnt]=v2;        } pair<ll,ll>ask (LL k) {int key=k%mod;        if (key<0) Key+=mod;        for (int i=h[key];i;i=next[i]) {if (s[i]==k) return Make_pair (M[i],p[i]);    }return Make_pair ( -1,-1); }}h;    void Get_prime () {mu[1]=1;phi[1]=1;            for (int i=2;i<=2000000;++i) {if (!vis[i]) {p[++cnt]=i;        Phi[i]=i-1;mu[i]=-1; } for (int j=1;j<=cnt; ++j) {if (1ll*p[j]*i>2000000) break;            int IP=I*P[J];            Vis[ip]=true;                if (i%p[j]==0) {phi[ip]=phi[i]*p[j];            Break        }mu[ip]=-mu[i];p hi[ip]=phi[i]* (p[j]-1); }} for (int i=2;i<=2000000;++i) phi[i]+=phi[i-1],mu[i]+=mu[i-1];}    Pair<ll,ll>sum (LL N) {if (n<=2000000) return Make_pair (Mu[n],phi[n]);    Pair<ll,ll>tmp=h.ask (n);    if (tmp.first!=-1) return tmp; LL a=1,b=1ll*n* (n+1)/2;    LL LA;        for (ll i=2;i<=n;i=la+1) {ll now=n/i;        La=n/now;        Tmp=sum (now);        a=a-1ll*tmp.first* (la-i+1);    b=b-1ll*tmp.second* (la-i+1);    }h.push (N,A,B); Return Make_pair (A, b);}    int main () {scanf ("%d", &t);    Get_prime ();        while (t--) {scanf ("%lld", &n);        Pair<ll,ll>ans=sum (n);    printf ("%lld%lld\n", Ans.second,ans.first); }return 0;}

HDU 5608

Qaq standard cannot be in standard Duchi sieve form

First n^2-3n+2 the prefix and we can O (1) to find out (the table tells me you will not square prefixes and formulas)

After we consider if pre-processing F, we set g (n) =n^2-3n+2

Can get g=f*i, and then get G*mu=f*i*mu, then F=G*MU

I am lazy, I do not know whether F is an integrable function (seemingly not)

Then direct O (NLOGN) of the contribution of the past, so that the pre-100w can be pre-processed F

Then use the Duchi sieve to find out the answer O (n^ (2/3))

#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include < algorithm>using namespace Std;const int Mod=1e9+7;const int mod=1333331;typedef long long ll;int T,n,inv1,inv2;bool VI S[1000010];int p[1000010],cnt=0;int mu[1000010];int f[1000010];struct hashmap{int h[MOD+10],cnt;int next[3000010]; int s[3000010],st[3000010];void push (int k,int v) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return;} ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=k;st[cnt]=v;} int ask (int k) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return st[i];} return-1;}} H;int pow_mod (int v,int p) {int tmp=1;while (p) {if (p&1) tmp=1ll*tmp*v%mod;v=1ll*v*v%mod;p>>=1;} return TMP;} void Get_prime () {mu[1]=1;for (int i=2;i<=1000000;++i) {if (!vis[i]) {p[++cnt]=i;mu[i]=-1;} for (int j=1;j<=cnt;++j) {if (1ll*p[j]*i>1000000) Break;int ip=i*p[j];vis[ip]=true;if (i%p[j]==0) break;mu[ip]=- Mu[i];}} return;} void Get_f () {for (int i=1;i<=1000000;++i) {int now= (1ll*i*i-3*i+2)%mod;int cnt=0;for (int j=i;j<=1000000;j+=i) {cnt++;f[j]=f[j]+now*mu[cnt];if (f[j]<0) f[j]+=mod;if (f[j]>= MoD) F[j]-=mod;}} for (int i=2;i<=1000000;++i) {f[i]+=f[i-1];if (f[i]>=mod) F[i]-=mod;} return;} int sum (int n) {if (n<=1000000) return f[n];int tmp=h.ask (n), if (tmp!=-1) return tmp;int a=1ll*n* (n+1)%mod* (2*n+1)%mod *inv1%mod; a=a-3ll*n* (n+1)%mod*inv2%mod;if (a<0) a+=mod; A=a+2*n%mod;if (A>=mod) a-=mod;int la;for (int i=2;i<=n;i=la+1) {int now=n/i;la=n/now; A=a-1ll*sum (n/i) * (la-i+1)%mod;if (a<0) A+=mod;} H.push (n,a); return A;} int main () {scanf ("%d", &t); Get_prime (); Get_f (); Inv1=pow_mod (6,mod-2); Inv2=pow_mod (2,mod-2); while (t--) {scanf ("%d", &n);p rintf ("%d\n", SUM (n));} return 0;}

The sum of 51Nod greatest common divisor

Seemingly online does not have the puzzle, then I will send a copy of it, maybe can cheat traffic

Notice that the problem is n and N, not N and M

We might as well enumerate greatest common divisor k

And because we know (I,J) =k was established and only when (I/K,J/K) =1 was established

Then we can transform the original formula into:

Set P (n) =sigma (phi (i))

Original =2*sigma (K*p (n/k))-n* (n+1)/2

The correctness of the transformation of the formula is obvious.

So we can find the value of P (n/k) using the Du sieve.

Since we know that the Duchi sieve solves all the P (k) values of all n's approximate k, only the O (n^ (2/3)) is required.

So we're going to have a chunk on the outside that doesn't affect the complexity of time.

Total time complexity O (sqrt (n) +n^ (2/3))

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include < cstdlib>using namespace Std;const int Mod=1e9+7;const int mod=1333331;typedef long long ll;int inv;int p[500010],cnt=0 ; int Phi[5000010];bool vis[5000010]; LL n;struct hashmap{int h[mod+10],cnt;int next[100010],st[100010]; ll s[100010];void push (ll K,int v) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return;} ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=k;st[cnt]=v;} int Ask (LL k) {int key=k%mod;for (int i=h[key];i;i=next[i]) {if (s[i]==k) return st[i];} return-1;}} H;int pow_mod (int v,int p) {int tmp=1;while (p) {if (p&1) tmp=1ll*tmp*v%mod;v=1ll*v*v%mod;p>>=1;} return TMP;} void Get_prime () {phi[1]=1;for (int i=2;i<=5000000;++i) {if (!vis[i]) {p[++cnt]=i;phi[i]=i-1;} for (int j=1;j<=cnt;++j) {if (1ll*p[j]*i>5000000) Break;int ip=i*p[j];vis[ip]=true;if (i%p[j]==0) {phi[ip]=phi[i ]*p[j];break;} phi[ip]=phi[i]* (p[j]-1);}} for (int i=2;i<=5000000;++i) {phi[i]+=phi[i-1];if (Phi[i]>=mod)Phi[i]-=mod;} return;} int sum (LL n) {if (n<=5000000) return phi[n];int tmp=h.ask (n); if (tmp!=-1) return tmp; ll La,k=n%mod;int a=k* (k+1)%mod*inv%mod;for (ll i=2;i<=n;i=la+1) {ll now=n/i;la=n/now; a=a-(la-i+1)%mod*sum (now)%mod;if (a<0) A+=mod;} H.push (n,a); return A;} int main () {scanf ("%lld", &n); Inv=pow_mod (2,mod-2); Get_prime (); ll La,ans=0;for (ll i=1;i<=n;i=la+1) {ll now=n/i;la=n/now;ans=ans+ (I+la)%mod* (la-i+1)%mod*inv%mod*sum (now)%mod; if (Ans>=mod) ans-=mod;} Ans<<=1;if (ans>=mod) ans-=mod; LL k=n%mod;ans=ans-k* (k+1)%mod*inv%mod;if (ans<0) ans+=mod;printf ("%lld\n", ans); return 0;}

Bzoj 4176

Seems to be a SDOI2015 of a problem of the enhanced version?

Next is a sad story, the name of the story is not to use the blog garden to write the price of the formula

First we have a conclusion:

Well, let's see, there are three of the conclusions I know, the simplest of which is the use of mathematical induction

Then the equation becomes (the equivalent of the E function is replaced by the MU function)

Then we enumerate K, and the equation is converted into

It's easy to see that the two sigma in the middle is actually the same thing.

Well, finally don't write this crooked formula, end of Qaq

The G function is about a number of functions, we are asking for the prefix of the number of functions and can do O (sqrt (n))

The practical practice is to enumerate each number I, (n/i) is the contribution of this number to the answer, the sum of blocks can be

Then we enumerate the whole K, do the block sum, a section of MU and we can use the Duchi sieve to fix

The time complexity of the Duchi sieve is O (n^ (2/3)), since the starting and ending points of the segment are approximate to n.

As for the two-time block summation stack appears to be sqrt (n) *sqrt (n) =n, but based on the time complexity analysis above

The time complexity is O (n^ (3/4)), so we're done with this problem.

(I must learn how to write the formula with a blog (too ugly, cover the face.) Dig pit ing))

When I wrote this question, I found a very funny thing.

It's the hash table of my previous topic. Push actually doesn't have to see if there was a push before

Just push it in, because it's been found and not put in.

The code ran on the Bzoj, and it was fast.

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include < Cstdlib>using namespace Std; const int Mod=1e9+7;const int mod=1333331;typedef long long ll;int n,inv;int mu[1000010];bool vis[1000010];int p[1000010] , cnt=0;    struct hashmap{int h[mod+10],cnt;    int next[100010];    int s[100010],st[100010];        void push (int k,int v) {int key=k%mod;        ++cnt;next[cnt]=h[key];h[key]=cnt;    S[cnt]=k;st[cnt]=v;        } int ask (int k) {int key=k%mod;        for (int i=h[key];i;i=next[i]) {if (s[i]==k) return st[i];    }return-1; }}h;    int pow_mod (int v,int p) {int tmp=1;        while (p) {if (p&1) Tmp=1ll*tmp*v%mod;    v=1ll*v*v%mod;p>>=1; }return tmp;}    void Get_prime () {mu[1]=1;            for (int i=2;i<=1000000;++i) {if (!vis[i]) {p[++cnt]=i;        Mu[i]=-1;            } for (int j=1;j<=cnt;++j) {if (1ll*p[j]*i>1000000) break; int Ip=i*p[j];            Vis[ip]=true;            if (i%p[j]==0) break;        Mu[ip]=-mu[i]; }} for (int i=2;i<=1000000;++i) mu[i]+=mu[i-1];}    int sum (int n) {if (n<=1000000) return mu[n];    int Tmp=h.ask (n);    if (tmp!=-1) return tmp;    int la,a=1;        for (int i=2;i<=n;i=la+1) {int now=n/i;        La=n/now;        a=a-1ll* (la-i+1) *sum (now)%mod;    if (a<0) A+=mod;    }h.push (N,a); return A;}    int g (int n) {int la,a=0;        for (int i=1;i<=n;i=la+1) {int now=n/i;        La=n/now;        a=a+1ll* (la-i+1) *now%mod;    if (a>=mod) A-=mod; }return 1ll*a*a%mod;}    int main () {scanf ("%d", &n);    Get_prime (); Inv=pow_mod (2,mod-2);    int la,ans=0;        for (int i=1;i<=n;i=la+1) {int now=n/i;        La=n/now;        ans=ans+1ll* (sum (LA)-sum (i-1)) *g (now)%mod;        if (ans>=mod) Ans-=mod;    if (ans<0) Ans+=mod;    }printf ("%d\n", (ans%mod+mod)%mod); return 0;

Em, wrap it up.

The Duchi sieve has very obvious characteristics:

1. Data range Features: 10^9,10^10,10^11

2, can solve the problem is to solve a function of the prefix and or a range of

But the premise is that the prefix and the Dirichlet convolution of the I function are better

3, in the case of pre-processing O (n^ (2/3)) of the time complexity of the O (sqrt (n)) values, that is, the approximate number of n all values

Because of the existence of memory, so in the computation of time complexity, the du sieve can not be simply multiplied with other things to calculate

4, must not forget the memory, must not forget the pretreatment

5, because of the particularity of the data range, so it is very easy to overflow the integer in the calculation process

At the time of writing must be carefully analyzed after the code, after the code is finished by the shooting or measuring the limit of data and other methods to test

Some of the pits left:

The sum of 51Nod least common multiple

51Nod average least common multiple

51Nod Sum of approximate

Sum of 51Nod weighted approximate sum

Bzoj 3512

Duchi Screening Study Summary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.