这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
2020-2021:teams:legal_string:jxm2001:数论_2 [2020/07/09 21:50] jxm2001 |
2020-2021:teams:legal_string:jxm2001:数论_2 [2020/07/27 22:56] (当前版本) jxm2001 ↷ 页面2020-2021:teams:legal_string:数论_2被移动至2020-2021:teams:legal_string:jxm2001:数论_2 |
||
---|---|---|---|
行 324: | 行 324: | ||
<hidden 查看代码> | <hidden 查看代码> | ||
<code cpp> | <code cpp> | ||
- | #include <cstdio> | ||
- | #include <iostream> | ||
- | #include <vector> | ||
- | #include <algorithm> | ||
- | #include <cstring> | ||
- | #include <cctype> | ||
- | #include <queue> | ||
- | #include <cmath> | ||
- | #define _for(i,a,b) for(int i=(a);i<(b);++i) | ||
- | #define _rep(i,a,b) for(int i=(a);i<=(b);++i) | ||
- | #define mem(a,b) memset((a),(b),sizeof(a)) | ||
- | using namespace std; | ||
- | typedef long long LL; | ||
- | inline int read_int(){ | ||
- | int t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline LL read_LL(){ | ||
- | LL t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline void write(LL x){ | ||
- | register char c[21],len=0; | ||
- | if(!x)return putchar('0'),void(); | ||
- | if(x<0)x=-x,putchar('-'); | ||
- | while(x)c[++len]=x%10,x/=10; | ||
- | while(len)putchar(c[len--]+48); | ||
- | } | ||
- | inline void space(LL x){write(x),putchar(' ');} | ||
- | inline void enter(LL x){write(x),putchar('\n');} | ||
const int MAXP=5e4+5; | const int MAXP=5e4+5; | ||
bool vis[MAXP]; | bool vis[MAXP]; | ||
行 421: | 行 387: | ||
<hidden 查看代码> | <hidden 查看代码> | ||
<code cpp> | <code cpp> | ||
- | #include <cstdio> | ||
- | #include <iostream> | ||
- | #include <vector> | ||
- | #include <algorithm> | ||
- | #include <cstring> | ||
- | #include <cctype> | ||
- | #include <queue> | ||
- | #include <cmath> | ||
- | #define _for(i,a,b) for(int i=(a);i<(b);++i) | ||
- | #define _rep(i,a,b) for(int i=(a);i<=(b);++i) | ||
- | #define mem(a,b) memset((a),(b),sizeof(a)) | ||
- | using namespace std; | ||
- | typedef long long LL; | ||
- | inline int read_int(){ | ||
- | int t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline LL read_LL(){ | ||
- | LL t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline void write(LL x){ | ||
- | register char c[21],len=0; | ||
- | if(!x)return putchar('0'),void(); | ||
- | if(x<0)x=-x,putchar('-'); | ||
- | while(x)c[++len]=x%10,x/=10; | ||
- | while(len)putchar(c[len--]+48); | ||
- | } | ||
- | inline void space(LL x){write(x),putchar(' ');} | ||
- | inline void enter(LL x){write(x),putchar('\n');} | ||
const int MAXP=5e4+5; | const int MAXP=5e4+5; | ||
bool vis[MAXP]; | bool vis[MAXP]; | ||
行 561: | 行 493: | ||
<hidden 查看代码> | <hidden 查看代码> | ||
<code cpp> | <code cpp> | ||
- | #include <iostream> | ||
- | #include <cstdio> | ||
- | #include <cstdlib> | ||
- | #include <algorithm> | ||
- | #include <string> | ||
- | #include <sstream> | ||
- | #include <cstring> | ||
- | #include <cctype> | ||
- | #include <cmath> | ||
- | #include <vector> | ||
- | #include <set> | ||
- | #include <map> | ||
- | #include <stack> | ||
- | #include <queue> | ||
- | #include <ctime> | ||
- | #include <cassert> | ||
- | #define _for(i,a,b) for(int i=(a);i<(b);++i) | ||
- | #define _rep(i,a,b) for(int i=(a);i<=(b);++i) | ||
- | #define mem(a,b) memset(a,b,sizeof(a)) | ||
- | using namespace std; | ||
- | typedef long long LL; | ||
- | inline int read_int(){ | ||
- | int t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline LL read_LL(){ | ||
- | LL t=0;bool sign=false;char c=getchar(); | ||
- | while(!isdigit(c)){sign|=c=='-';c=getchar();} | ||
- | while(isdigit(c)){t=(t<<1)+(t<<3)+(c&15);c=getchar();} | ||
- | return sign?-t:t; | ||
- | } | ||
- | inline char get_char(){ | ||
- | char c=getchar(); | ||
- | while(c==' '||c=='\n'||c=='\r')c=getchar(); | ||
- | return c; | ||
- | } | ||
- | inline void write(LL x){ | ||
- | register char c[21],len=0; | ||
- | if(!x)return putchar('0'),void(); | ||
- | if(x<0)x=-x,putchar('-'); | ||
- | while(x)c[++len]=x%10,x/=10; | ||
- | while(len)putchar(c[len--]+48); | ||
- | } | ||
- | inline void space(LL x){write(x),putchar(' ');} | ||
- | inline void enter(LL x){write(x),putchar('\n');} | ||
const int MAXP=5e4+5; | const int MAXP=5e4+5; | ||
bool vis[MAXP]; | bool vis[MAXP]; | ||
行 658: | 行 543: | ||
} | } | ||
return 0; | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> | ||
+ | |||
+ | ==== 习题3 ==== | ||
+ | |||
+ | [[https://www.luogu.com.cn/problem/P3704|洛谷p3704]] | ||
+ | |||
+ | === 题意 === | ||
+ | |||
+ | 共 $T$ 组询问,每次询问 $\prod_{i=1}^n\prod_{j=1}^mf_{\text{gcd}(i,j)}\bmod p$,其中 $f$ 表示斐波那契数列,且$f_0=0,f_1=1$。 | ||
+ | |||
+ | === 题解 === | ||
+ | |||
+ | 不妨设 $n\le m$。 | ||
+ | |||
+ | 首先按套路把 $\text{gcd}$ 换成莫比乌斯函数,有 | ||
+ | |||
+ | \begin{equation}\prod_{i=1}^n\prod_{j=1}^mf_{\text{gcd}(i,j)}=\prod_{d=1}^n\prod_{i=1}^n\prod_{j=1}^mf_d[(i,j)==d]=\prod_{d=1}^nf_d^{\sum_{i=1}^n\sum_{j=1}^m[(i,j)==d]}=\prod_{d=1}^n f_d^{\sum_{k=1}^{\lfloor\frac nd\rfloor}\mu(k)\lfloor\frac n{kd}\rfloor\lfloor\frac m{kd}\rfloor}\end{equation} | ||
+ | |||
+ | 令 $T=kd$,有 | ||
+ | |||
+ | \begin{equation}\prod_{d=1}^n f_d^{\sum_{k=1}^{\lfloor\frac nd\rfloor}\mu(k)\lfloor\frac n{kd}\rfloor\lfloor\frac m{kd}\rfloor}=\prod_{T=1}^n\left(\prod_{d\mid T}f_d^{\mu(\frac Td)}\right)^{\lfloor\frac nT\rfloor\lfloor\frac mT\rfloor}\end{equation} | ||
+ | |||
+ | 外部指数部分考虑数论分块。内部可以先预处理,枚举 $d$,对每个 $T=kd$ 计算贡献。 | ||
+ | |||
+ | 预处理时间复杂度 $O(n\log p+\sum_{i=1}^n \frac ni)=O(n(\log n+\log p))$,询问的时间复杂度为 $O(T\sqrt n\log p)$。 | ||
+ | |||
+ | <hidden 查看代码> | ||
+ | <code cpp> | ||
+ | const int MAXN=1e6+5,mod=1e9+7; | ||
+ | bool vis[MAXN]; | ||
+ | int prime[MAXN],mu[MAXN],f[MAXN],s[MAXN],s_inv[MAXN],cnt; | ||
+ | int quick_pow(int a,int b){ | ||
+ | LL t=1; | ||
+ | while(b){ | ||
+ | if(b&1) | ||
+ | t=t*a%mod; | ||
+ | a=1LL*a*a%mod; | ||
+ | b>>=1; | ||
+ | } | ||
+ | return t%mod; | ||
+ | } | ||
+ | void Pre(){ | ||
+ | vis[1]=true,mu[1]=1;f[0]=0,f[1]=1; | ||
+ | _for(i,2,MAXN){ | ||
+ | f[i]=(f[i-2]+f[i-1])%mod; | ||
+ | if(!vis[i])mu[i]=-1,prime[cnt++]=i; | ||
+ | for(int j=0;j<cnt&&i*prime[j]<MAXN;j++){ | ||
+ | vis[i*prime[j]]=true; | ||
+ | if(i%prime[j]) | ||
+ | mu[i*prime[j]]=-mu[i]; | ||
+ | else{ | ||
+ | mu[i*prime[j]]=0; | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | _for(i,0,MAXN) | ||
+ | s[i]=s_inv[i]=1; | ||
+ | int base[3]={1,1,1},*t=base+1; | ||
+ | _for(i,2,MAXN){ | ||
+ | t[-1]=quick_pow(f[i],mod-2),t[1]=f[i]; | ||
+ | for(int j=1;j*i<MAXN;j++){ | ||
+ | s[i*j]=1LL*s[i*j]*t[mu[j]]%mod; | ||
+ | s_inv[i*j]=1LL*s_inv[i*j]*t[-mu[j]]%mod; | ||
+ | } | ||
+ | } | ||
+ | _for(i,2,MAXN) | ||
+ | s[i]=1LL*s[i]*s[i-1]%mod,s_inv[i]=1LL*s_inv[i]*s_inv[i-1]%mod; | ||
+ | } | ||
+ | int cal(int n,int m){ | ||
+ | int lef=1,rig; | ||
+ | LL ans=1; | ||
+ | while(lef<=n){ | ||
+ | rig=min(n/(n/lef),m/(m/lef)); | ||
+ | ans=ans*quick_pow(1LL*s[rig]*s_inv[lef-1]%mod,1LL*(n/lef)*(m/lef)%(mod-1))%mod; | ||
+ | lef=rig+1; | ||
+ | } | ||
+ | return (ans+mod)%mod; | ||
+ | } | ||
+ | int main() | ||
+ | { | ||
+ | int t=read_int(),n,m; | ||
+ | Pre(); | ||
+ | while(t--){ | ||
+ | n=read_int(),m=read_int(); | ||
+ | enter(cal(min(n,m),max(n,m))); | ||
+ | } | ||
+ | return 0; | ||
} | } | ||
</code> | </code> | ||
</hidden> | </hidden> | ||