CCPC 2019 網絡賽 HDU 6706 huntian oy
標籤
- 奇奇怪怪的數論結論
- 杜教篩
前言
- 我的csdn和博客園是同步的,歡迎來訪danzh-博客園~
簡明題意
- 給定n,a,b,求:
思路
- 首先有一個結論:
- 上面的結論對於i,j互質是成立的。關注這題,條件式裏就有[gcd(i,j)=1],所以我們可以直接替換:(由於ab互質,所以指數直接去掉)
- (其實我比賽的時候猜出來gcd那一坨就等於i-j,然後我寫了個暴力驗證一下,發現有些數不相等,當時情急,就沒往這方面想了,好難過)
- 推到這裏,就太簡單了。接下來我們我們把減法分離開:
- 然後分別求一下這兩個式子。第一個式子比較好求,重點是第二個式子。
這個式子的推導過程放在我的博客《數論公式總結》裏面了
- 所以原式就等於
- 好了,n<=1e9,暴力去算和式會超時。這裏杜教篩。
- 令,。我們杜教篩,構造g:
- 現在難點就在於怎麼找g函數。找g函數,我們一般先把狄利克雷展開:
- 所以很顯然了,我們取g=id,卷積就是:
- 而(這個相當於,用卷積很好證明),所以:
- 所以杜教篩的式子:
- 然後就能很輕鬆地杜教篩啦~然而T了…
- 上面的式子如果需要求積性函數的前綴和,那麼大家肯定會寫一個線性篩。而這裏沒有,是不是就代表不需要預處理呢?其實還是需要的,要預處理出的前綴和,才能降低杜教篩的複雜度。
注意事項
- 注意溢出問題
總結
- 杜教篩在分塊的那一部分有減法操作,記得那裏的減法操作不要寫-=,因爲那裏的減法也要取模…
AC代碼
#include<cstdio>
#include<unordered_map>
using namespace std;
const int maxn = 5e6 + 10;
const int mod = 1e9 + 7;
int ksm(int a, int b)
{
int ans = 1, base = a;
while (b)
{
if (b & 1)
ans = 1ll * ans * base % mod;
b >>= 1;
base = 1ll * base * base % mod;
}
return ans;
}
int inv6, inv2;
int prime[maxn], phi[maxn], pre[maxn];
bool no_prime[maxn];
int shai(int n)
{
int cnt = 0;
no_prime[1] = phi[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!no_prime[i])
prime[++cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && i * prime[j] <= n; j++)
{
no_prime[prime[j] * i] = 1;
phi[prime[j] * i] = i % prime[j] == 0 ? phi[i] * prime[j] : phi[i] * (prime[j] - 1);
if (i % prime[j] == 0) break;
}
}
for (int i = 1; i <= n; i++)
pre[i] = (1ll * pre[i - 1] + 1ll * i * phi[i] % mod) % mod;
return cnt;
}
unordered_map<int, int> rec;
int S(int n)
{
if (n <= maxn - 10) return pre[n];
if (rec[n]) return rec[n];
long long ans = 1ll * n * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod;
int l = 2, r = n;
while (l <= n)
{
r = n / (n / l);
ans = ((ans - 1ll * (l + r) * (r - l + 1) % mod * inv2 % mod * S(n / l) % mod) % mod + mod) % mod;
l = r + 1;
}
return rec[n] = ans;
}
void solve()
{
inv6 = ksm(6, mod - 2);
inv2 = ksm(2, mod - 2);
shai(maxn - 10);
int t;
scanf("%d", &t);
while (t--)
{
int n, a, b;
scanf("%d%d%d", &n, &a, &b);
printf("%lld\n", 1ll * (S(n) - 1 + mod) % mod * inv2 % mod);
}
}
int main()
{
solve();
return 0;
}