【YBTOJ高效進階 21190】尤拉函式(數學)
阿新 • • 發佈:2021-11-19
給你一些數 a1~an,然後要你求: 在每個數中選一個因子,它們的積的尤拉函式的結果的和。
的貢獻。
尤拉函式
題目連結:YBTOJ高效進階 21190
題目大意
給你一些數 a1~an,然後要你求:
在每個數中選一個因子,它們的積的尤拉函式的結果的和。
思路
由於是尤拉函式,我們通過線性篩求它的方法,自然想到把每個質數分開來解決。
那就變成了你每個數可以貢獻 \(0\sim k_{p,i}\)(\(k_{p,i}\) 是 \(p\) 在 \(i\) 質因數分解的時候出現的次數)
那你就考慮 DP,要麼是這次是第一次貢獻,要麼是這一次不是。
那你是第一次貢獻就是直接加上(記得要把 \(1\sim k_{p,i}\) 的貢獻都加上)
然後不是第一次的話就是之前的答案乘上 \(0\sim k_{p,i}\)
然後記得要加上什麼都不選的情況,然後每個質數的結果就可以了。
程式碼
#include<cstdio> #include<vector> #define ll long long #define mo 1000000007 using namespace std; int n, a[100001]; int prime[1000001]; int np[10000001], pl[10000001]; vector <int> nm[1000001]; ll ans, f[2000001]; ll slove(int now) {//分別處理每個質數 for (int i = 0; i < nm[now].size(); i++) { f[i + 1] = 0; ll noww = 0, di = 1; for (int j = 0; j < nm[now][i]; j++) { noww = (noww + di) % mo; di = di * prime[now] % mo; } f[i + 1] = noww * (prime[now] - 1) % mo;//這次有新的 noww = (noww + di) % mo; f[i + 1] = (f[i + 1] + f[i] * noww % mo) % mo;//之前就有加上的 } return (f[nm[now].size()] + 1) % mo;//加上什麼都不選的 } int main() { // freopen("varphi.in", "r", stdin); // freopen("varphi.out", "w", stdout); for (int i = 2; i <= 10000000; i++) { if (!np[i]) { np[i] = i; prime[++prime[0]] = i; pl[i] = prime[0]; } for (int j = 1; j <= prime[0] && i * prime[j] <= 10000000; j++) { np[i * prime[j]] = prime[j]; if (i % prime[j] == 0) break; } } scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); int noww = a[i]; while (noww != 1) {//分解一下質因數 int now = np[noww], ti = 0; while (np[noww] == now) { noww /= now; ti++; } nm[pl[now]].push_back(ti); } } ans = 1; for (int i = 1; i <= prime[0]; i++) { ans = ans * slove(i) % mo; } printf("%lld", ans); return 0; }