[航海协会]稀疏阶乘问题
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[航海协会]稀疏阶乘问题相关的知识,希望对你有一定的参考价值。
稀疏阶乘问题
题目概述
题解
我们发现
F
(
x
)
F(x)
F(x)是
m
m
m倍数是可以看作
F
(
x
)
%
m
=
0
F(x)\\%m=0
F(x)%m=0的,也就是说
∏
(
x
−
k
2
)
\\prod(x-k^2)
∏(x−k2)中包含了
m
m
m的所有质因子。
对每个质因子单独考虑。
如果
m
=
∏
i
=
1
k
p
i
m=\\prod_i=1^k p_i
m=∏i=1kpi,我们的
F
(
x
)
=
0
F(x)=0
F(x)=0就相当于
∀
i
∈
[
1
,
k
]
,
∃
j
2
<
x
,
x
≡
j
2
(
m
o
d
p
i
)
\\forall i\\in[1,k],\\exist j^2< x,x\\equiv j^2\\pmodp_i
∀i∈[1,k],∃j2<x,x≡j2(modpi)。
一种简单的思路是我们记录下来
m
n
i
,
j
mn_i,j
mni,j表示取模
p
i
p_i
pi余
j
j
j的最小完全平方数。
显然有
[
F
(
x
)
%
m
=
0
]
=
⋀
i
=
1
k
[
x
>
m
n
i
,
x
%
p
i
]
[F(x)\\%m =0]=\\bigwedge_i=1^k[x>mn_i,x\\%p_i]
[F(x)%m=0]=⋀i=1k[x>mni,x%pi]。
但如果
m
=
∏
i
=
1
k
p
i
k
i
m=\\prod_i=1^k p_i^k_i
m=∏i=1kpiki呢?这样许多
k
2
%
p
=
a
k^2\\% p=a
k2%p=a的完全平方数贡献在一起可以抵一个
k
2
%
p
k
=
a
+
p
b
k^2\\%p^k=a+pb
k2%pk=a+pb的效果。
诶,可以发现,我们只需要不超过
k
i
k_i
ki个这样的数就行了。
我们不妨暴力枚举
c
p
i
+
r
,
c
∈
[
1
,
k
i
]
cp_i+r,c\\in[1,k_i]
cpi+r,c∈[1,ki],把它们贡献到所有满足
j
%
p
i
=
r
2
%
p
i
j\\%p_i=r^2\\%p_i
j%pi=r2%pi的
m
n
i
,
j
mn_i,j
mni,j上,记录每一个至少要撑到哪一个
c
p
i
+
r
cp_i+r
cpi+r,也就是找到最小的
l
i
m
lim
lim使得
∏
l
=
0
l
i
m
(
j
−
l
p
i
−
r
)
≡
0
(
m
o
d
p
i
k
i
)
\\prod_l=0^lim(j-lp_i-r)\\equiv 0\\pmodp_i^k_i
∏l=0lim(j−lpi−r)≡0(modpiki),反正有
l
i
m
<
k
i
⩽
log
m
lim<k_i\\leqslant \\log m
lim<ki⩽logm,可以直接暴力找。
弄完这些后我们可以发现,对于任意的
x
x
x,只有当
x
>
max
i
=
1
k
m
n
i
,
x
%
m
x>\\max_i=1^kmn_i,x\\%m
x>maxi=1kmni,x%m
时
F
(
x
)
F(x)
F(x)才为
0
0
0,我们求一下这个最大值构成的区间与
[
l
,
r
]
[l,r]
[l,r]之间的交集中有多少个
%
m
=
x
\\% m=x
%m=x的数即可。
时间复杂度 O ( m log m ) O\\left(m\\log m\\right) O(mlogm)差不多吧。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
typedef unsigned int uint;
#define MAXN 1000005
#define MAXM 15
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
LL gcd(LL a,LL b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
int m,p[MAXM],a[MAXM],f[MAXM],cntp,num[MAXN];
LL mn[MAXM][MAXN],l,r,ans;
int main()
//freopen("sfac.in","r",stdin);
//freopen("sfac.out","w",stdout);
read(l);read(r);read(m);l--;
for(int i=2,t=m;i<=t;i++)if(t%i==0)
[航海协会]树