你来迟了…
当你看到篇博客的时候,这个世界已经发生了翻天覆地的变化。
好吧其实就是开学了
这是寒假集训的最后一篇学习笔记了。
当然前面有两篇blog被我咕掉了,之后应该会咕回来的。
题目选自[集训小记]2020寒假集训(1.19-1.22)day4 数论部分。
1.BZOJ 4173 数学
欧拉函数
n , m ≤ 1 0 15 n,m\leq 10^{15} n,m≤1015
比较简单的题目。
S
(
n
,
m
)
S(n,m)
S(n,m)这个集合的条件很不好处理,因此我们需要化简一下。
m
m
o
d
k
+
n
m
o
d
k
≥
k
m
−
k
×
⌊
m
k
⌋
+
n
−
k
×
⌊
n
k
⌋
≥
k
m
+
n
≥
k
∗
(
1
+
k
×
⌊
m
k
⌋
+
k
×
⌊
n
k
⌋
)
⌊
m
+
n
k
⌋
≥
1
+
⌊
m
k
⌋
+
⌊
n
k
⌋
⌊
m
+
n
k
⌋
−
⌊
m
k
⌋
−
⌊
n
k
⌋
=
1
⌊
m
+
n
k
⌋
φ
(
k
)
−
⌊
m
k
⌋
φ
(
k
)
−
⌊
n
k
⌋
φ
(
k
)
=
φ
(
k
)
m\mod k+n\mod k≥k\\ m-k\times \lfloor \frac{m}{k}\rfloor+n-k\times \lfloor \frac{n}{k}\rfloor≥k\\ m+n≥k*(1+k\times \lfloor \frac{m}{k}\rfloor+k\times \lfloor \frac{n}{k}\rfloor)\\ \lfloor \frac{m+n}{k}\rfloor≥1+\lfloor \frac{m}{k}\rfloor+\lfloor \frac{n}{k}\rfloor\\ \lfloor \frac{m+n}{k}\rfloor-\lfloor \frac{m}{k}\rfloor-\lfloor \frac{n}{k}\rfloor=1\\ \lfloor \frac{m+n}{k}\rfloorφ(k)-\lfloor \frac{m}{k}\rfloorφ(k)-\lfloor \frac{n}{k}\rfloorφ(k)=φ(k)\\
mmodk+nmodk≥km−k×⌊km⌋+n−k×⌊kn⌋≥km+n≥k∗(1+k×⌊km⌋+k×⌊kn⌋)⌊km+n⌋≥1+⌊km⌋+⌊kn⌋⌊km+n⌋−⌊km⌋−⌊kn⌋=1⌊km+n⌋φ(k)−⌊km⌋φ(k)−⌊kn⌋φ(k)=φ(k)
因此
∑
k
∈
S
(
n
,
m
)
φ
(
k
)
=
∑
i
=
1
n
+
m
⌊
m
+
n
k
⌋
φ
(
k
)
−
∑
i
=
1
m
⌊
m
k
⌋
φ
(
k
)
−
∑
i
=
1
n
⌊
n
k
⌋
φ
(
k
)
\sum_{k\in S(n,m)}φ(k)=\sum^{n+m}_{i=1}\lfloor \frac{m+n}{k}\rfloorφ(k)-\sum^{m}_{i=1}\lfloor \frac{m}{k}\rfloorφ(k)-\sum^{n}_{i=1}\lfloor \frac{n}{k}\rfloorφ(k)
k∈S(n,m)∑φ(k)=i=1∑n+m⌊km+n⌋φ(k)−i=1∑m⌊km⌋φ(k)−i=1∑n⌊kn⌋φ(k)
为什么要这样做呢…因为
∑
k
=
1
n
i
=
∑
k
=
1
n
∑
d
∣
k
φ
(
d
)
=
∑
d
=
1
n
⌊
n
d
⌋
φ
(
d
)
\sum^n_{k=1}i=\sum^n_{k=1}\sum_{d|k}φ(d)=\sum^n_{d=1}\lfloor \frac{n}{d}\rfloorφ(d)
k=1∑ni=k=1∑nd∣k∑φ(d)=d=1∑n⌊dn⌋φ(d)
然后答案就是
φ
(
n
)
⋅
φ
(
m
)
n
m
φ(n)·φ(m)nm
φ(n)⋅φ(m)nm
/*Lower_Rating*/
/*number theory*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
using namespace std;
#define LL unsigned long long
#define DB double
#define MOD 998244353
#define Pr pair<int,int>
#define X first
#define Y second
#define MAXN 200000
#define MAXK 8000
#define eps 1e-10
#define INF 4294967298LL
#define mem(x,p) memset(x,p,sizeof(x))
LL read(){
LL x=0,F=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')F=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*F;
}
inline int add(register int a,register int b){return (a+b>=MOD)?a+b-MOD:a+b;}
inline int dec(register int a,register int b){return (a-b<0)?a-b+MOD:a-b;}
inline int mul(register LL a,register int b){a*=b;return (a>=MOD)?a%MOD:a;}
inline int fst_pow(register int a,register int b){
int res=1;
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}return res;
}
inline int inv(register int a){return fst_pow(a,MOD-2);}
int phi(LL x){
int res=1;
for(LL i=2;i*i<=x;i++)
if(x%i==0){
x/=i;res=mul(res,i-1);
while(x%i==0)
x/=i,res=mul(res,i);
}
if(x!=1)res=mul(res,(x-1)%MOD);
return res;
}
LL n,m;
int main()
{
n=read(),m=read();
printf("%d",mul(mul(phi(n),phi(m)),mul(n%MOD,m%MOD)));
}
2.[51nod 1479]小Y的数论题
小Y喜欢研究数论,并且喜欢提一些奇怪的问题。
这天他找了三个两两互质的数 a , b , c a, b, c a,b,c,以及另一个数 m m m, 现在他希望找到三个 ( 0 , m ) (0, m) (0,m)范围内的整数 x , y , z x, y, z x,y,z,使得 ( x a + y b ) m o d m = ( z c ) m o d m (x^a+y^b)\mod m=(z^c) \mod m (xa+yb)modm=(zc)modm。
构造题就要从最简单的方向想起。
我们知道
2
t
+
2
t
=
2
t
+
1
2^t+2^t=2^{t+1}
2t+2t=2t+1,显然我们可以从这里入手。
首先我们先构造
(
2
a
k
)
b
+
(
2
b
k
)
a
=
2
k
a
b
+
1
(2^{ak})^{b}+(2^{bk})^a=2^{kab+1}
(2ak)b+(2bk)a=2kab+1。
这样我们就只用满足
z
c
z^c
zc这一项了。
设
z
=
2
l
z=2^l
z=2l,那么就有
k
⋅
a
⋅
b
−
c
⋅
l
=
1
k·a·b-c·l=1
k⋅a⋅b−c⋅l=1。
显然我们可以直接用exgcd解决。
有个大坑,原题要求我们
x
,
y
,
z
x,y,z
x,y,z要在
(
0
,
m
)
(0,m)
(0,m)之间,当
m
=
2
t
m=2^t
m=2t时,我们的解中可能会有零。
所以我们需要单独构造…
[讲个笑话,我开着ull调了半天]
/*Lower_Rating*/
/*number theory*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
using namespace std;
#define LL long long
#define DB double
#define MOD 998244353
#define Pr pair<int,int>
#define X first
#define Y second
#define MAXN 200000
#define MAXK 8000
#define eps 1e-10
#define INF 4294967298LL
#define mem(x,p) memset(x,p,sizeof(x))
LL read(){
LL x=0,F=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')F=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*F;
}
inline int add(register int a,register int b){return (a+b>=MOD)?a+b-MOD:a+b;}
inline int dec(register int a,register int b){return (a-b<0)?a-b+MOD:a-b;}
inline int mul(register LL a,register int b){a*=b;return (a>=MOD)?a%MOD:a;}
int T;
LL m,a,b,c;
LL exgcd(LL a,LL b,LL &X,LL &Y){
if(b==0){X=1,Y=0;return a;}
LL x0,y0,G;
G=exgcd(b,a%b,x0,y0);
X=y0,Y=x0-(a/b)*y0;
return G;
}
LL fst_pow(LL a,LL b){
LL res=1;
while(b){
if(b&1)res=1LL*res*a%m;
a=1LL*a*a%m;
b>>=1;
}return res;
}
int main()
{
T=read();
while(T--){
m=read();
a=read(),b=read(),c=read();
LL k,l;
if(m&(m-1)){
exgcd(a*b,c,k,l),k=-k;
while(k<0||l<0)k+=c,l+=a*b;
printf("%lld %lld %lld\n",fst_pow(2,k*b),fst_pow(2,k*a),fst_pow(2,l));
}else{
if(a>1)printf("%d %d %d\n",m/2,1,1);
else if(b>1)printf("%d %d %d\n",1,m/2,1);
else if(c>1)printf("%d %d %d\n",m/2,m/2,m/2);
else printf("%d %d %d\n",1,1,2);
}
}
}
3.[51nod1245] Binomial Coefficients Revenge
给出 M M M和质数 p p p,求 ( 0 M ) , ( 1 M ) . . . . . . ( M M ) \binom{0}{M}, \binom{1}{M}......\binom{M}{M} (M0),(M1)......(MM)这 M + 1 M + 1 M+1个数中,有多少数不是 p p p的倍数,有多少是 p p p的倍数但不是 p 2 p^2 p2的倍数,有多少是 p 2 p^2 p2的倍数但不是 p 3 p^3 p3的倍数…。
1 ≤ T ≤ 5000 , 2 ≤ M , P ≤ 1 0 18 1 \leq T \leq 5000,2\leq\ M,P \leq10^{18} 1≤T≤5000,2≤ M,P≤1018
这题的关键就是库默尔定理吧…
我们都知道质数
p
p
p在
n
!
n!
n!出现次数是
∑
i
=
1
n
⌊
n
p
i
⌋
\sum^n_{i=1}\lfloor \frac{n}{p^i}\rfloor
∑i=1n⌊pin⌋。
组合数
(
m
n
)
\binom{m}{n}
(nm)的贡献就是
∑
i
=
1
n
⌊
n
p
i
⌋
−
⌊
m
p
i
⌋
−
⌊
n
−
m
p
i
⌋
\sum^n_{i=1}\lfloor \frac{n}{p^i}\rfloor-\lfloor \frac{m}{p^i}\rfloor-\lfloor \frac{n-m}{p^i}\rfloor
∑i=1n⌊pin⌋−⌊pim⌋−⌊pin−m⌋。
根据第1题的结论,我们知道
⌊
n
p
i
⌋
−
⌊
m
p
i
⌋
−
⌊
n
−
m
p
i
⌋
\lfloor \frac{n}{p^i}\rfloor-\lfloor \frac{m}{p^i}\rfloor-\lfloor \frac{n-m}{p^i}\rfloor
⌊pin⌋−⌊pim⌋−⌊pin−m⌋只能为1或者0。
根据库默尔定理有
n
m
o
d
p
i
+
1
<
m
m
o
d
p
i
+
1
n\mod p^{i+1}<m\mod p^{i+1}
nmodpi+1<mmodpi+1时取到1。
因此我们将
n
n
n看成
p
p
p进制下的数,那么我们统计
n
n
n的后缀小于
m
m
m的后缀的次数就行了。
所以我们直接数位dp,令
d
p
[
i
]
[
j
]
[
0
/
1
]
dp[i][j][0/1]
dp[i][j][0/1]为当前是从低到高第
i
i
i位,现在已经有
j
j
j次取到1,上一次是否取到1(因为这一次是否取到和上一次是否取到1有关系)
m
m
m的个数。
由于
m
≤
n
m\leq n
m≤n,所以我们最终只需输出
d
p
[
e
n
d
]
[
i
]
[
0
]
dp[end][i][0]
dp[end][i][0](
e
n
d
end
end为最后一位)就好了。
复杂度:
O
(
T
⋅
l
o
g
P
2
M
)
O(T·log^2_{P}M)
O(T⋅logP2M)。
/*Lower_Rating*/
/*number theory*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
using namespace std;
#define LL long long
#define DB double
#define MOD 998244353
#define Pr pair<int,int>
#define X first
#define Y second
#define MAXN 100
#define MAXK 8000
#define eps 1e-10
#define INF 4294967298LL
#define mem(x,p) memset(x,p,sizeof(x))
LL read(){
LL x=0,F=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')F=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*F;
}
inline int add(register int a,register int b){return (a+b>=MOD)?a+b-MOD:a+b;}
inline int dec(register int a,register int b){return (a-b<0)?a-b+MOD:a-b;}
inline int mul(register LL a,register int b){a*=b;return (a>=MOD)?a%MOD:a;}
int T;
LL n,p,a[MAXN+5];int m;
LL dp[MAXN+5][MAXN+5][2];
int main()
{
T=read();
while(T--){
mem(dp,0);
m=0,n=read(),p=read();
LL x=n;
while(x)a[++m]=x%p,x/=p;
dp[1][1][1]=p-a[1]-1,dp[1][0][0]=a[1]+1;
for(int i=2;i<=m;i++)
for(int j=0;j<i;j++){
dp[i][j][0]=(a[i]+1)*dp[i-1][j][0]+a[i]*dp[i-1][j][1];
dp[i][j+1][1]=(p-a[i]-1)*dp[i-1][j][0]+(p-a[i])*dp[i-1][j][1];
}
for(int i=0;i<=m&&dp[m][i][0];i++)
printf("%lld ",dp[m][i][0]);
puts("");
}
}
4.[51nod 1132]覆盖数字的数量V2
给出 2 2 2个整数 A A A, B B B。可以使用任意次。再给出一段从 X − Y X - Y X−Y的区间T,任选若干个 A A A, B B B做加法,可以覆盖区间T中多少个不同的整数。
对不起,它被咕了