bzoj2154(莫比乌斯反演)
生活随笔
收集整理的這篇文章主要介紹了
bzoj2154(莫比乌斯反演)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
又是一道經典題.
1.學習了下O(n) 的做法。
// // main.cpp // bzoj2154 // // Created by New_Life on 16/7/7. // Copyright ? 2016年 chenhuan001. All rights reserved. // #include <iostream> #include <string.h> #include <stdio.h> using namespace std;#define N 10001000 #define MOD 20101009//--莫比烏斯反演函數--// //說明:利用線性素數篩選順便求了個mu //注釋部分為求從區間[1,b]和區間[1,d]中取兩個數,互質對數O(n^0.5) //復雜度:O(n) int mu[N]; long long sum[N]; int prime[N]; bool mark[N];void mobus() {int pcnt=0;memset(mark,0,sizeof(mark));mu[1] = 1;for(int i=2;i<N;i++){if(mark[i] == 0){prime[pcnt++] = i;mu[i] = -1;}for(int j=0;j<pcnt && i*prime[j]<N;j++){int tmp = i*prime[j];mark[tmp] = 1;if( i%prime[j] == 0 ){mu[tmp] = 0;break;}mu[tmp] = mu[i]*-1;}}for(int i=1;i<N;i++){sum[i] += sum[i-1]+(long long)mu[i]*i*i;sum[i] %= MOD;} }long long gaobili(long long b,long long d) {if(b<=0||d<=0) return 0;long long m = min(b,d);long long ans = 0;while(m>=1){long long tb = b/( b/m +1 )+1;long long td = d/( d/m +1 )+1;//前進的最大位置long long tm = max(tb,td);ans += (sum[m]-sum[tm-1])*(((b/m+1)*(b/m)/2)%MOD)%MOD*(((d/m+1)*(d/m)/2)%MOD)%MOD ;ans %= MOD;m = tm-1;}return ans; } //等差數列求和模板,[a1,a1+d,...,an] long long allsum(long long a1,long long an,long long n) {if(n%2==0)return (a1+an)*(n/2);else return ((a1+an)/2)*n; }int main(int argc, const char * argv[]) {mobus();int b,d;while(scanf("%d%d",&b,&d)!=EOF){int m = min(b,d);long long ans = 0;while(m>=1){int tb = b/( b/m +1 )+1;int td = d/( d/m +1 )+1;//前進的最大位置int tm = max(tb,td);ans += allsum(tm,m,m-tm+1)%MOD*gaobili(b/m, d/m)%MOD;ans %= MOD;m = tm-1;}cout<<(ans+MOD)%MOD<<endl;}return 0; } /*4 5*/?
2.O(n)預處理,每次查詢n^0.5
因為bzoj2693題目找不到了,所以直接用了這題來測試。
這題首先是一個經典的公式變形。 交換連加時變量的位置。
而根據第二個重要的性質,乘性函數的乘除之后還是乘性函數。(加減并不是)
所以后面的連加部分也是乘性函數,這時只需要的單獨看只含一個因子的時候,因為里面含有u(i),所以對于D=x^k(x是素因子)只有當i = 1 或 x 時不為0,所以
后面的為x^k(1-x)。這時可以在線性篩選時順便求出來。
**************************************************************Problem: 2154User: chenhuan001Language: C++Result: AcceptedTime:16668 msMemory:93088 kb ****************************************************************/#include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> #include <iostream> using namespace std; //--莫比烏斯反演函數--// //說明:利用線性素數篩選順便求了個mu //注釋部分為求從區間[1,b]和區間[1,d]中取兩個數,互質對數O(n^0.5) //復雜度:O(n) #define N 10000010 bool mark[N]; int prime[N/10];long long sum[N];#define MOD 20101009void mobus() {int pcnt=0;sum[1] = 1;for(int i=2;i<N;i++){if(mark[i] == 0){prime[pcnt++] = i;sum[i] = (long long)i*(1-i)%MOD;}for(int j=0;j<pcnt && i*prime[j]<N;j++){int tmp = i*prime[j];mark[tmp] = 1;if( i%prime[j] == 0 ){sum[tmp] = sum[i]*prime[j];sum[tmp] %= MOD;break;}else{sum[tmp] = sum[i]*(sum[prime[j]])%MOD;}}}for(int i=1;i<N;i++)sum[i] = (sum[i]+sum[i-1])%MOD; }long long gaobili(int b,int d) {if(b<=0||d<=0) return 0;long long m = min(b,d);long long ans = 0;while(m>=1){long long tb = b/( b/m +1 )+1;long long td = d/( d/m +1 )+1;//前進的最大位置long long tm = max(tb,td);ans += (sum[m]-sum[tm-1])*(((b/m+1)*(b/m)/2)%MOD)%MOD*(((d/m+1)*(d/m)/2)%MOD)%MOD;ans %= MOD;m = tm-1;}return (ans+MOD)%MOD; } int main() {mobus();int b,d;while(scanf("%d%d",&b,&d)!=EOF){printf("%d\n",(int)gaobili(b,d));}return 0; }?
至此mobus大概都刷了一遍,原以為很復雜的東西,其實也不是很難。以后面對的題目可能有更多的公式變形,或許難在找出莫比烏斯模型。但基本的也就是這些方法了。
治好了多年的公式恐懼癥。。
?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的bzoj2154(莫比乌斯反演)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编码格式(乱码)
- 下一篇: 腾讯 FPS 游戏《穿越火线》15 周年