日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【NOI2016】循环之美【莫比乌斯反演】【整除分块】【杜教筛】【类杜教筛】

發布時間:2023/12/3 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【NOI2016】循环之美【莫比乌斯反演】【整除分块】【杜教筛】【类杜教筛】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

傳送門

題意:給定n,m,kn,m,kn,m,k,求1≤x≤n,1≤y≤m1\leq x\leq n,1\leq y\leq m1xn,1ymxyx \over yyx?中數值不同的純循環小數或整數的個數。

n≤109,m≤109,k≤2×103n \leq 10^9,m\leq10^9,k\leq2\times10^3n109,m109,k2×103

顯然只需要考慮最簡分數即gcd?(x,y)=1\gcd(x,y)=1gcd(x,y)=1的情況

容(bu)易(yong)證明,xyx\over yyx?滿足題意當且僅當gcd?(y,k)=1\gcd(y,k)=1gcd(y,k)=1

所以

Ans=∑i=1N∑j=1M[gcd?(i,j)=1][gcd?(j,k)=1]Ans=\sum_{i=1}^N\sum_{j=1}^M[\gcd(i,j)=1][\gcd(j,k)=1]Ans=i=1N?j=1M?[gcd(i,j)=1][gcd(j,k)=1]

換下順序

=∑j=1M[gcd?(j,k)=1]∑i=1N[gcd?(i,j)=1]=\sum_{j=1}^M[\gcd(j,k)=1]\sum_{i=1}^N[\gcd(i,j)=1]=j=1M?[gcd(j,k)=1]i=1N?[gcd(i,j)=1]

把后面反演掉,前面不管

=∑j=1M[gcd?(j,k)=1]∑i=1N∑d∣i,d∣jμ(d)=\sum_{j=1}^M[\gcd(j,k)=1]\sum_{i=1}^N\sum_{d\mid i,d\mid j}\mu(d)=j=1M?[gcd(j,k)=1]i=1N?di,dj?μ(d)

枚舉ddd

=∑d=1N?Nd?μ(d)∑d∣jj≤M[gcd?(j,k)=1]=\sum_{d=1}^N\lfloor \frac{N}ozvdkddzhkzd\rfloor\mu(d)\sum_{d\mid j}^{j\leq M}[\gcd(j,k)=1]=d=1N??dN??μ(d)djjM?[gcd(j,k)=1]

換成枚舉jjjddd的多少倍

=∑d=1N?Nd?μ(d)∑j=1?Md?[gcd?(jd,k)=1]=\sum_{d=1}^N\lfloor \frac{N}ozvdkddzhkzd\rfloor\mu(d)\sum_{j=1}^{\lfloor\frac{M}d{}\rfloor}[\gcd(jd,k)=1]=d=1N??dN??μ(d)j=1?dM???[gcd(jd,k)=1]

gcd?\gcdgcd拆開

=∑d=1N?Nd?μ(d)∑j=1?Md?[gcd?(j,k)=1][gcd?(d,k)=1]=\sum_{d=1}^N\lfloor \frac{N}ozvdkddzhkzd\rfloor\mu(d)\sum_{j=1}^{\lfloor\frac{M}d{}\rfloor}[\gcd(j,k)=1][\gcd(d,k)=1]=d=1N??dN??μ(d)j=1?dM???[gcd(j,k)=1][gcd(d,k)=1]

=∑d=1N?Nd?μ(d)[gcd?(d,k)=1]∑j=1?Md?[gcd?(j,k)=1]=\sum_{d=1}^N\lfloor \frac{N}ozvdkddzhkzd\rfloor\mu(d)[\gcd(d,k)=1]\sum_{j=1}^{\lfloor\frac{M}d{}\rfloor}[\gcd(j,k)=1]=d=1N??dN??μ(d)[gcd(d,k)=1]j=1?dM???[gcd(j,k)=1]

f(n,k)=∑i=1n[gcd?(i,k)=1]f(n,k)=\sum_{i=1}^n[\gcd(i,k)=1]f(n,k)=i=1n?[gcd(i,k)=1]

由于kkk只有200020002000,并且gcd?(i,k)=gcd?(i%k,k)\gcd(i,k)=\gcd(i\%k,k)gcd(i,k)=gcd(i%k,k),所以瞎預處理一下就可以算出來

這樣

Ans=∑d=1N?Nd?μ(d)[gcd?(d,k)=1]f(?Md?,k)Ans=\sum_{d=1}^N\lfloor \frac{N}ozvdkddzhkzd\rfloor\mu(d)[\gcd(d,k)=1]f(\lfloor\frac{M}ozvdkddzhkzd\rfloor,k)Ans=d=1N??dN??μ(d)[gcd(d,k)=1]f(?dM??,k)

這是個整除分塊的形式,我們只需要想辦法算出

g(n,k)=∑i=1nμ(i)[gcd?(i,k)=1]g(n,k)=\sum_{i=1}^n\mu(i)[\gcd(i,k)=1]g(n,k)=i=1n?μ(i)[gcd(i,k)=1]

這個可以反演

g(n,k)=∑i=1nμ(i)∑d∣i,d∣kμ(d)g(n,k)=\sum_{i=1}^n\mu(i)\sum_{d\mid i,d\mid k}\mu(d)g(n,k)=i=1n?μ(i)di,dk?μ(d)

枚舉ddd

g(n,k)=∑d∣kμ(d)∑d∣ii≤nμ(i)g(n,k)=\sum_{d\mid k}\mu(d)\sum_{d\mid i}^{i\leq n}\mu(i)g(n,k)=dk?μ(d)diin?μ(i)

枚舉倍數

g(n,k)=∑d∣kμ(d)∑i=1?nd?μ(id)g(n,k)=\sum_{d\mid k}\mu(d)\sum_{i=1}^{\lfloor\frac{n}ozvdkddzhkzd\rfloor}\mu(id)g(n,k)=dk?μ(d)i=1?dn???μ(id)

前方高能

觀察μ(id)\mu(id)μ(id),發現如果gcd?(i,d)≠1\gcd(i,d)\neq1gcd(i,d)?=1,μ(id)\mu(id)μ(id)一定等于000

所以……我們可以丟一個[gcd?(i,d)=1][\gcd(i,d)=1][gcd(i,d)=1]進去

g(n,k)=∑d∣kμ(d)∑i=1?nd?μ(id)[gcd?(i,d)=1]g(n,k)=\sum_{d\mid k}\mu(d)\sum_{i=1}^{\lfloor\frac{n}ozvdkddzhkzd\rfloor}\mu(id)[\gcd(i,d)=1]g(n,k)=dk?μ(d)i=1?dn???μ(id)[gcd(i,d)=1]

由于μ\muμ是積性函數,有這個限制就可以拆開了,然后把μ(d)\mu(d)μ(d)丟前面去

g(n,k)=∑d∣kμ2(d)∑i=1?nd?μ(i)[gcd?(i,d)=1]g(n,k)=\sum_{d\mid k}\mu^2(d)\sum_{i=1}^{\lfloor\frac{n}ozvdkddzhkzd\rfloor}\mu(i)[\gcd(i,d)=1]g(n,k)=dk?μ2(d)i=1?dn???μ(i)[gcd(i,d)=1]

后面那個有沒有很眼熟?

g(n,k)=∑d∣kμ2(d)g(?nd?,d)g(n,k)=\sum_{d\mid k}\mu^2(d)g(\lfloor\frac{n}ozvdkddzhkzd\rfloor,d)g(n,k)=dk?μ2(d)g(?dn??,d)

然后就可以遞歸了

邊界:

n=0n=0n=0時,g(n,k)=0g(n,k)=0g(n,k)=0

k=1k=1k=1時,我們發現無法遞歸

所以寫個杜教篩算一下就可以了

復雜度O(能過)O(能過)O()

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <utility> #include <map> using namespace std; typedef long long ll; const int N=1e6; int n,m,k; int np[N+5],pl[N],cnt; int mu[N+5],sum[N+5]; void init() {np[1]=mu[1]=1;for (int i=2;i<=N;i++){if (!np[i]) pl[++cnt]=i,mu[i]=-1;for (int j=1,x;(x=i*pl[j])<=N;j++){np[x]=1;if (i%pl[j]==0){mu[x]=0;break;}else mu[x]=-mu[i];}}for (int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i]; } map<int,int> ms; int getms(int n) {if (n<=N) return sum[n];map<int,int>::iterator p;if ((p=ms.find(n))!=ms.end()) return p->second;int ans=1;for (int l=2,r;l<=n;l=r+1){r=n/(n/l);ans-=(r-l+1)*getms(n/l);}ms.insert(make_pair(n,ans));return ans; } int x[2005]; int gcd(int a,int b){return b? gcd(b,a%b):a;} inline int f(const int& n){return n/k*x[k]+x[n%k];} map<pair<int,int>,int> sg; int g(int n,int k) {if (n==0) return 0;if (k==1) return getms(n);map<pair<int,int>,int>::iterator p;pair<int,int> pi=make_pair(n,k);if ((p=sg.find(pi))!=sg.end()) return p->second;int ans=0;for (int i=1;i*i<=k;i++)if (k%i==0){if (mu[i]) ans+=g(n/i,i);if (i*i<k&&mu[k/i]) ans+=g(n/(k/i),k/i);}sg.insert(make_pair(pi,ans));return ans; } int main() {init();scanf("%d%d%d",&n,&m,&k);for (int i=1;i<=k;i++) x[i]=x[i-1]+(gcd(i,k)==1);ll ans=0;for (int l=1,r;l<=n&&l<=m;l=r+1){r=min(n/(n/l),m/(m/l));ans+=(ll)(n/l)*f(m/l)*(g(r,k)-g(l-1,k));}printf("%lld\n",ans);return 0; }

總結

以上是生活随笔為你收集整理的【NOI2016】循环之美【莫比乌斯反演】【整除分块】【杜教筛】【类杜教筛】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。