数学数论专项练习 day 60
A
显然只需要考虑质因子。
首先 \(k\) 只有一个质因子可以特判,有两个可以 exgcd
有三个及其以上那么最小的一个 \(\le 10^5\),同余最短路即可。
B
考虑一个序列 $\lbrace x|x=a_ib_i^t,t\in \mathbb{N}\rbrace $,对于一个质因子提出了怎样的限制?
设 \(a_i,b_i\) 在质因数 \(p\) 的指数分别是 \(c_{i,p},d_{i,p}\)
则 Ans 设为 \(\prod p_i^{r_i}\)
必然有对于每个 \(p\),有:
-
\(\forall i,c_{i,p}\le r_p\)
-
\(\forall i,r_p\equiv c_{i,p}(\bmod d_{i,p})\)
-
\(\exists k,\forall p,r_p=c_{i,p}+k·d_{i,p}\)
也就是要求 \(b\) 的指数相同
等价于:
\(\forall p_1,p_2,i,d_{i,p}>0,\frac{r_{p_1}-c_{i,p_1}}{d_{i,p_1}}=\frac{r_{p_2}-c_{i,p_2}}{d_{i,p_2}}\)
限制条件 \(2\) 应当是可解的,会得到一个 \(r_p\equiv h_p(\bmod m_p)\),限制条件 \(1\) 可以通过调整下界来满足
但是限制条件 \(3\) 就有一点那个
其实可以通过 \(h_p,m_p\) 来反过来对 \(a_ib_i^{k_i}\) 中的 \(k_i\) 提出限制。
类如 \(k_i\equiv x_i(\bmod t_i)\) 这种东西,其实也就是最初的 \(h_p\) 给出的限制,还有后面的 \(m_p\) 给出的限制,这是一个 \(p\) 给一个序列的限制,一个序列的 \(k\) 可以由这些线性同余方程组解出来
解出来之后呢,由于每个 \(k_i\) 是独立的,但是我们要求最终的解答是一样的,所以每个 \(k_i\) 可以通过质因子建立一些关系,这显然也是丢番图方程
嗯貌似可以高斯消元
然后取一组最小的解出来就好了
太TMD扯淡了这个题写起来
\(n\le 100?\)
C
硬算指定死,不过因为 \(C\le 10^6\),所以可以处理出两个区间每个数字的出现次数,这可以暴力找循环节。注意循环节前面还有一段未进入循环节的部分
而且有 \(\frac{p}{q}+\frac{q}{p}\) 由于呈现倒数关系所以值最大是 \(C+1\)。
考虑设 \(f(x,y)=\frac{x}{y}+\frac{y}{x}\),考虑求解 \(\sum[\lceil f(x_i,y_i)\rceil \ge k]\)
考虑到这玩意是对勾函数,那么对于一个 \(x_i\) 而言是可以利用二次函数解出一段区间的
现在还是 \(O(C^2)\),考虑优化
注意到对勾函数存在分界点,也就是 \(x=y\) 的时候,不妨钦定 \(x<y\),枚举 \(x\),则这个对勾函数随着 \(y\) 增加而增加,最多取到 \(\frac{C}{y}\),所以是调和级数复杂度。
D
首先 \(\gcd a_i\) 的肯定是解,然后根据欧拉定理显然不存在大于 \(n\) 的质数符合条件了
那么考虑枚举 \(\le n\) 的质数,利用欧拉定理将其变为 \(p-1\) 阶多项式后判断系数模 \(p\) 是否是全零,同时需要有 \(p|a_0\)。
这东西疑似充要
E
拜谢粉方方,粉方方好闪
显然可以等效为 \(aFib_n+bFib_{n+1}\equiv 0(\bmod m)\)
自然地除掉 \(\gcd(a,b,m)\) 同时 \(b\) 进行移项,变为 \(a',b',m'\),则有:
也就相当于 \(a'Fib_n=b'Fib_{n+1}+km'\)。
同时除掉 \(\gcd(a',m')\) 显然也成立,这就要求 \(\gcd(a',m')|b’Fib_{n+1},\gcd(a',b',m')=1\implies \gcd(a',m')|Fib_{n+1}\)。
类似地,也可以得出 \(\gcd(b',m')|Fib_n\),又因为有 \(\gcd(Fib_n,Fib_{n+1})=1\),所以类似有 \(\gcd(Fib_n,m')|b',\gcd(Fib_{n+1},m')|a'\)
则有:\(\gcd(Fib_{n+1},m')|a',\gcd(a',m')|Fib_{n+1}\implies \gcd(Fib_{n+1},m')=\gcd(a',Fib_{n+1},m')\)
类似地可以有 \(\gcd(Fib_{n+1},m')=\gcd(a',m')\)
也有 \(\gcd(Fib_n,m')=\gcd(b',m')\)
不妨设 \(x=\gcd(Fib_n,m'),y=\gcd(Fib_{n+1},m')\)
则显然有 \(\gcd(x,y)=1\),且 \((xy)|m',y|(a'Fib_n),x|(b'Fib_{n+1})\)
所以给原同余式整体除掉 \(xy\) 是可以的,且除掉之后所有数字就互质了
互质就可以求逆元了,同时也说明了 \((\frac{a'}{y},\frac{b'}{x},\frac{m'}{xy})\) 与 \((\frac{Fib_{n+1}}{x},\frac{Fib_n}{y},\frac{m'}{xy})\) 是对应的,因为可以互推。
注意到后面的三元组个数与 \(m\) 的约数和同阶(显然 \(Fib\) 数列循环节长度与模数同阶,手玩易证)
可以暴力处理出来直接哈希表/map 回答询问即可。
F
显然你三个方向两个向外一个向内,所以向外的状态向向内的状态连边,则可以变成一颗二叉树,而原题等价于问两个点之间的距离,显然我们只需要求出 dep
和 lca
即可。
可以考虑倍增,显然我们可以在类似辗转相除法地计算 \(k\) 级祖先,这就好了
G
妙啊,是我不会的题
首先由于 \(n\ge 2\),故可以考虑 CRT,设 \(i\neq j,x=a+bi+k_i(c+di)=a+bj+k_j(c+dj)\)
可以得出 \(b(i-j)=(k_j-k_i)c+(jk_j-ik_i)d\)
由于 \(i-j\) 是可以任意取的,譬如取 \(1\),而根据裴属定理,后面显然可以给出 \(\gcd(c,d)|b\),当然也因为后面不为零
这是一个判断无解的条件
那么我们设 \(g=\gcd(b,c,d)=\gcd(c,d)\)。
一步很妙的就是拿出常数 \(a\) 将其变为 \(a\bmod g,a-(a\bmod g)\),这一步即使在同余意义下也当然是对的,可以考虑暴力Excrt最终合并后的式子,\(a\) 不影响。
那么就可以令 \(a'=\lfloor\frac{a}{g}\rfloor,b'=\frac{b}{g},c'=\frac{c}{g},d'=\frac{d}{g}\)
我们求解 \(x'\equiv a'+b'i(\bmod c'+d'i),i\in [0,n-1]\cap \mathbb{Z}\)
则答案可以还原为 \(x=x'g+(a\bmod g)\)。
这是因为你给Excrt过程中的每个 \(M_i(c+d_i)\) 除掉了因子 \(g\),则你乘回去对于每个式子仍然成立(写成不定方程就方便多了)。
则有:
可以看到我们利用乘法手段将整个同余式右侧化成了定值,则满足如上式子等价于满足 \(M=lcm(c'+d'i),d'x\equiv d'a'-c'b'(\bmod M)\)
我们所需最小非负整数解 \(x’\),则也即只需要求得一个 \(d'|(d'a'-c'b'+yM)\) 满足 \(d'a'-c'b'+yM\) 是 \(\ge 0\) 的第一个符合要求的值。
显然我们只需要枚举一个循环节,也就是 \(d\) 个连续整数的 \(y\)
我们可以进行如下处理:
-
\(d'a'-c'b'<0\)
- 当 \(M\) 极大时(严格意义上讲 \(\ge|d'a'-c'b'|\) 即可,为了方便编程不妨设
inf=2e12
)
我们可以枚举 \([1,d']\) 以内的整数作为 \(y\) 计算答案
- 当 \(M\) 较小时,直接对 \(d'a'-c'b'\) 取模 \(M\) 的最小非负值(这时候 \(M\) 是可以存下的)
- 当 \(M\) 极大时(严格意义上讲 \(\ge|d'a'-c'b'|\) 即可,为了方便编程不妨设
-
\(d’a'-c'b'\ge 0\)
- 当 \(M\) 极大时,我们可以枚举 \([0,d'-1]\) 的整数作为 \(y\)。
- 当 \(M\) 较小时,我们先取 \(d’a'-c'b'\) 取模 \(M\) 的最小非负值,然后枚举 \([0,d'-1]\) 的整数作为 \(y\)
这样的枚举策略显然可以保证有解就可以找到一组最小的合法解。
最后我们求出 \(d’a'-c'b'+yM\) 模 998244353
的值之后,再求 \(d'\) 在模 998244353
意义下的逆元,计算答案即可。
那么问题就只剩下三个
- 求解 \(M\) 模 \(d’\) 的值
- 求解 \(M\) 模
998244353
的值 - 判断 \(M\) 是否的“极大的”
不妨设 \(w_i=c'+d'i\)
注意到 \(\gcd(w_i,w_j)=\gcd(c'+d'i,(i-j)d')\),可以有 \(\gcd(w_i,w_j)|(i-j)d'\)
同时由于 \(\gcd(c',d')=1\),而 \(\gcd(w_i,d')=\gcd(c',d')=1\),所以说 \(\gcd(w_i,w_j,d')=1\),也就是 \(\gcd(w_i,w_j)\) 与 \(d’\) 互质。
那么可以得到 \(\gcd(w_i,w_j)|(i-j)\),而 \(i-j<n\),所以不同 \(w\) 之间的共同质因子必然是 \([2,n]\cap \mathbb{Z}\) 的质数。
所以我们筛掉 \(n\) 以内的质数(\(w\) 除掉相应质数)后,\(w\) 之间两两互质。
在这一步里,\(M\) 就可以拆分为每个 \(n\) 以内的质数的最大次幂以及除掉这些质数后余下的 \(w\) 的积。
至于筛掉质数这一步,不妨枚举 \(p\),也就是要求所有的 \(i\) 满足 \(c'+d'i\equiv 0(\bmod p)\implies d'i+pj=-c'\),可以利用 exgcd
求出 \(i\) 的通解进行暴力计算最大次幂和除法。
这一步的复杂度是不超过 \(O(n\log n+n\log d')\) 的,这是因为
-
\(\gcd(d',p)\neq 1\) 时,\(p\) 是 \(d’\) 的质因子,此时 \(\gcd(d',p)=p\),\(i\) 的循环节长度是 \(1\)
这样的 \(p\) 只有不超过 \(\log d\) 个
-
\(\gcd(d',p)=1\) 时,\(i\) 的循环节长度是 \(p\),也就是有 \(\lfloor\frac{n}{p}\rfloor\) 个,根据调和级数的知识这必然不超过 \(O(n\log n)\)
通过这一步筛除质数后乘上所有剩下的 \(w\) 就可以计算出 \(M\) 模 \(d'\) 和 模 998244353
的值了,至于是否是极大的,在乘法过程中判断即可。
实现:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=2e12,mod=998244353;
int Md=1,Mans=1,Mup=1,N,A,B,C,D;
int w[1050050],v[1050500];
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;return a;
}
int d=exgcd(b,a%b,x,y);
int z=x;x=y,y=z-(a/b)*y;
return d;
}
signed main(){
// ios::sync_with_stdio(false);
cin>>N>>A>>B>>C>>D;
int g=__gcd(C,D);if(B%g){
cout<<"-1\n";return 0;
}
int SurA=A%g;A/=g;B/=g,C/=g,D/=g;
for(int i=0;i<N;++i)w[i]=C+D*i;
for(int i=2;i<=N;++i){
if(!v[i]){
int p=i;
for(int j=i;j<=N;j+=i)v[j]=1;
//x*p+y*d=-c
if(C%__gcd(p,D))continue;
int x,y;int d=exgcd(p,D,x,y);
int len=p/d;y=y*(-(C/d)%len)%len;
y=(y%len+len)%len;
int mx=0;
// cout<<p<<": ";
for(int k=y;k<N;k+=len){
int c=0;
// cout<<k<<" "<<C+D*k<<"\n";
while(w[k]%p==0)w[k]/=p,++c;
mx=max(mx,c);
}
while(mx--){
Md=Md*p%D;
Mans=Mans*p%mod;
if(Mup>inf/p)Mup=inf+1;
else Mup=min(Mup*p,inf+1);
}
}
}
for(int i=0;i<N;++i)if(w[i]>1){
Md=Md*(w[i]%D)%D;
Mans=Mans*(w[i]%mod)%mod;
if(Mup>inf/w[i])Mup=inf+1;
else Mup=min(Mup*w[i],inf+1);
// cout<<w[i]<<" "<<i<<"\n";
}
// cout<<"prepared\n";
Mup=min(Mup,inf+1);
int tmp=A*D-B*C;
if(Mup!=inf+1)tmp=(tmp%Mup+Mup)%Mup;
auto power=[&](int a,int b)->int{
a%=mod;
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
};
// cout<<"pw "<<" "<<Md<<" "<<Mup<<' '<<Mans<<"\n";
for(int y=0;y<=D;++y){
// cout<<y<<"\n";
if(tmp<0&&y==0)continue;
if((tmp+y*Md%D)%D)continue;
// cout<<"Find\n";
int ans=(y*(Mans%mod)+tmp%mod)%mod;
ans=ans*power(D,mod-2)%mod;
ans=ans*g%mod;
ans=(ans+SurA)%mod;
cout<<ans<<"\n";return 0;
}
cout<<"-1\n";
return 0;
}