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