jzoj3509-倒霉的小C【gcd,欧拉函数】
正題
大意
畫n條線,每次坐標變換為(x+n,y+(?1)(i+1)?i)(i=1~n)(x+n,y+(-1)^{(i+1)}*i) \ \ \ (i=1\sim n)(x+n,y+(?1)(i+1)?i)???(i=1~n)。給出n,求線穿過的格點數。
解題思路
首先我們想穿過格點的問題,我們可以無視方向,然后每次就當從(0,0)(0,0)(0,0)到(n,i)(n,i)(n,i)劃一條線。然后我們可以發現穿過的格點數(算上起點)就是gcd(n,i)gcd(n,i)gcd(n,i),因為每次都會穿過(n/j,i/j)(j=1~gcd(n,i))(n/j,i/j)\ \ \ (j=1\sim gcd(n,i))(n/j,i/j)???(j=1~gcd(n,i))這些點。
然后我們可以知道答案就是
1+∑i=1ngcd(n,i)1+\sum_{i=1}^n gcd(n,i)1+i=1∑n?gcd(n,i)
但是暴力枚舉會超時,我們需要想別的方法
∑i=1ngcd(n,i)=d\sum_{i=1}^n gcd(n,i)=di=1∑n?gcd(n,i)=d
=>∑d=1nd?∑i=1n(gcd(i,n)==d)=>\sum_{d=1}^n d*\sum ^n_{i=1}(gcd(i,n)==d)=>d=1∑n?d?i=1∑n?(gcd(i,n)==d)
∑d=1nd?∑i=1ngcd(i/d,n/d)=1\sum_{d=1}^n d*\sum ^n_{i=1}gcd(i/d,n/d)=1d=1∑n?d?i=1∑n?gcd(i/d,n/d)=1
因為要求gcd(i/d,n/d)=1gcd(i/d,n/d)=1gcd(i/d,n/d)=1,所以i的個數就是φ(n/d)\varphi(n/d)φ(n/d)
所以答案就是
∑d=1nd×φ(n/d)\sum_{d=1}^n d\times \varphi(n/d)d=1∑n?d×φ(n/d)
由于要求n/dn/dn/d是整數,所以我們可以化為
1+∑d∣nd×φ(n/d)1+\sum_{d|n} d\times \varphi(n/d)1+d∣n∑?d×φ(n/d)
然后暴力枚舉約數和暴力求歐拉函數值時間復雜度為O(nlogn)O(\sqrt n\ \ log\ n)O(n???log?n)
代碼
#include<cstdio> #include<algorithm> #define ll long long using namespace std; ll n,ans=1; ll phi(ll n)//求歐拉函數 {ll ans=n;for (ll i=2;i*i<=n;i++)if (n%i==0){ans=ans/i*(i-1);while (n%i==0) n/=i;}if (n>1) ans=ans/n*(n-1);return ans; } int main() {//freopen("beats.in","r",stdin);//freopen("beats.out","w",stdout);scanf("%lld",&n);for (ll i=1;i*i<=n;i++){if (!(n%i)) {ans+=phi(n/i)*i;if (i*i!=n) ans+=n/i*phi(i);}//求約數}printf("%lld",ans);return 0; }總結
以上是生活随笔為你收集整理的jzoj3509-倒霉的小C【gcd,欧拉函数】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样自己建站如何在自己电脑上建网站
- 下一篇: Mate 60 系列销售强劲,消息称华为