分数取模
利用费马小定理
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p-1}≡1(mod p)
ap−1≡1(modp)
则
a
∗
b
−
n
≡
a
∗
b
p
−
n
−
1
m
o
d
p
a*b^{-n} ≡ a*b^{p-n-1} mod p
a∗b−n≡a∗bp−n−1modp
b(p-n-1)用快速幂取模得出
例如CF1452D
最后答案是f(n)/2n
对998244353取模
ans = f[n]*qpow(2,mod-n-1,mod)%mod;
完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353 ;
const int N = 2e5 + 5;
int f[N];
ll qpow(ll a, ll b, ll p)
{
ll x = 1;
a %= p;
while (b)
{
if (b&1) x = x*a%p;
b >>= 1;
a =a*a%p;
}
return x;
}
int main()
{
int n;
cin >> n;
f[1] = f[2] = 1;
for (int i = 3; i <= n ;i++)
{
f[i] = (f[i-1] + f[i-2])%mod;
}
ll ans = f[n]*qpow(2,mod-n-1,mod)%mod;
cout << ans;
}
欧拉筛
复杂度
O
(
n
)
O(n)
O(n)
p
r
i
m
e
[
0
]
prime[0]
prime[0]是计数用的,也就是欧拉函数的值(或许这就是他叫欧拉筛的原因?)
void Prime()
{
mem(visit,0);
mem(prime, 0);
for (int i = 2;i <= N; i++) {
if (!visit[i]) {
prime[++prime[0]] = i;
}
for (int j = 1; j <=prime[0] && i*prime[j] <= N; j++)
{
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
例如2018ICPC南京
这里用埃式筛就会超
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
int visit[N],prime[N],a[N];
vector<int> v[N];
void Prime()
{
mem(visit,0);
mem(prime, 0);
for (int i = 2;i <= N; i++) {
if (!visit[i]) {
prime[++prime[0]] = i;
}
for (int j = 1; j <=prime[0] && i*prime[j] <= N; j++)
{
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
void divide(int pos)
{
int x = a[pos];
for (int i = 1; prime[i]*prime[i] <= x; i++)
{
if (x % prime[i] == 0)
{
v[prime[i]].push_back(pos);
while(x %prime[i] == 0)
x /= prime[i];
}
}
if(x > 1) v[x].push_back(pos);
}
int main()
{
ll n,ans = 0;
cin >> n;
Prime();
for (int i = 1; i <= n ; i++)
{
cin >> a[i];
divide(i);
}
for (int i = 1; i < prime[0] ;i++)
{
int len = v[prime[i]].size();
if(len != 0)
{
ans = ans + (n - v[prime[i]][0] + 1)*v[prime[i]][0];
for (int j = 1; j < len ; j++)
{
ans = ans + (n - v[prime[i]][j] + 1) * (v[prime[i]][j] - v[prime[i]][j - 1]);
}
}
}
cout << ans;
}