【考试总结】2022-04-11


争辩

\(M_{i,j}\) 非空需要满足 \(j\le i+1\)

不难发现如果序列中有两个以上相同的数字那么一定可以通过两面包夹来得到一个不降的序列,同时在 \(n=2\) 时不合法的序列只能是 2 1

尝试将 \(3\) 放到序列里面使得通过操作将 \(3\) 放到末尾后剩下 2 1,分成 \(3\) 直接添加到末尾和通过 \((1,3)\) 移位后制造 2 1 3

那么我们发现了一个通过枚举 \(i+1\) 得位置从 \(i\) 转移到 \(i+1\) 的方法,设此时需要记录末尾元素和倒数第二个元素的值

注意这两个一定有一个是 \(i\),所以记录另一个的值和位置即可,可以 \(\Theta(n^2)\) 来递推实现

Code Display
const int N=5010;
int n,a1,a2;
int M[N][N],f[2][N][2];
signed main(){
    freopen("a.in","r",stdin); freopen("a.out","w",stdout);
    n=read(); a1=read(); a2=read();
    M[1][1]=a1; M[1][2]=a2;
    for(int i=2;i<=n;++i){
        for(int j=1;j<=n;++j) M[i][j]=add(M[i-1][j],mul(M[i-1][j-1],M[i-1][j-1]));
    }
    int Mult=1;
    for(int i=1;i<=n;++i){
        int sum=0;
        for(int j=1;j<=i+1;++j) ckadd(sum,M[i][j]);
        ckmul(Mult,sum);
    }
    if(n==1) printf("%lld 0\n",Mult),exit(0);
    int cur=0;
    f[cur][1][0]=1;
    for(int i=2;i

分解

对着式子添加最小因子可以发现 \(p\not |\ n,W(n\times p^e)=W(n)\varphi(p^e)+p\sigma_1(n)\)

使用 \(\min 25\) 筛计算:

第一部分可以先预处理 \(\sigma_1(n),W(n)\) 在质数处点值前缀和

同时在第二部分同时返回 \((\sum W,\sum \sigma_1)\) 来进行转移

Code Display
const int N=2e5+10;
int pri[N],cnt,n,id1[N],id2[N],block;
bool fl[N];
inline int get_id(int x){return x>block?id2[n/x]:id1[x];}
int sum0[N],sum1[N],g1[N],g2[N],val[N],tot;
// sum0 -> W
// sum1 -> sigma
// g1 -> F(x)=1
// g2 -> F(x)=x
inline pair solve(int n,int id){
    if(pri[id]>n||id>cnt) return {0,0};
    pair res={del(g1[get_id(n)],sum1[id-1]),del(g2[get_id(n)],sum0[id-1])};
    for(int i=id;pri[i]*pri[i]<=n&&i<=cnt;++i){
        int phi=pri[i]-1,sig=pri[i]+1;
        int e=1,pe=pri[i];
        while(pe<=n){
            pair ret=solve(n/pe,i+1);
            ckadd(res.fir,mul(sig%mod,ret.fir));
            ckadd(res.sec,mul(phi%mod,ret.sec));
            ckadd(res.sec,mul(pri[i],ret.fir));
            if(e>1) ckadd(res.fir,sig),ckadd(res.sec,pri[i]);
            sig=sig*pri[i]+1; phi*=pri[i]; 
            pe*=pri[i],++e;
        }
    }
    return res;
}
signed main(){
    freopen("b.in","r",stdin); freopen("b.out","w",stdout);
    n=read(); block=sqrt(n)+100;   
    for(int i=2;i<=block;++i){
        if(!fl[i]){
            pri[++cnt]=i;
            sum0[cnt]=add(sum0[cnt-1],i);
            sum1[cnt]=add(sum1[cnt-1],i+1);
        }
        for(int j=1;j<=cnt&&pri[j]*i<=block;++j){
            fl[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
    for(int l=1,r;l<=n;l=r+1){
        r=n/(val[++tot]=n/l);
        g1[tot]=del(val[tot]%mod,1);
        g2[tot]=del(val[tot]%mod*((val[tot]+1)%mod)%mod*(mod+1)/2%mod,1);
        if(val[tot]<=block) id1[val[tot]]=tot;
        else id2[r]=tot;
    }
    for(int i=1;i<=cnt;++i){
        for(int j=1;pri[i]*pri[i]<=val[j];++j){
            ckdel(g1[j],del(g1[get_id(val[j]/pri[i])],i-1));
            ckdel(g2[j],mul(pri[i],del(g2[get_id(val[j]/pri[i])],sum0[i-1])));
        }
    }
    for(int i=1;i<=tot;++i) ckadd(g1[i],g2[i]);
    print(add(solve(n,1).sec,1));
    return 0;
}

GCD

\(g_n=gcd(f_n,f_{n+1})\),可以通过辗转相减得到 \(g_n=3gcd(4f_{n-1},3f_{n-1}+4f_{n-2})=3gcd(f_{n-1},4f_{n-2})=3g_{n-2}\) (最后一个等号是因为所有 \(f_i\) 是奇数)

接着通过辗转相减来将 \(gcd(af_n+bf_{n+1},cf_{n}+df_{n+1})\) 消成 \(gcd(Af_{n}+Bf_{n+1},Cf_{n})\)

此时注意如果 \(B\) 或者 \(C\)\(0\) 那么都是平凡但是需要讨论的 \(\rm case\)

尝试先行计算 \(\displaystyle G=gcd\left(\frac{f_{n}}{g_n},B\right)=\frac{gcd(Af_{n}+Bf_{n+1},f_n)}{g_n}\)

这本质上是计算 \(\dfrac{f_n}{g_n}\)\(\mod B\) 意义下的数值,注意到 \(3\) 可能没有逆元,所以通过

\[3\begin{bmatrix}f_{2k+1}\\f_{2k}\end{bmatrix}\begin{bmatrix}31\ \ 3\\36\ \ 4\end{bmatrix}=\begin{bmatrix}f_{2k+3}\\f_{2k+2}\end{bmatrix} \]

来进行 \(3\) 的消去

接下来进行和式变换得到答案的形式:

\[\begin{aligned}&gcd(Af_n+Bf_{n+1},Cf_{n+1})\\=&G\times g_n\times gcd\left(\frac{A\frac{f_n}{g_n}+B\frac{f_{n+1}}{g_n}}{G},C\right)\end{aligned} \]

此时需要求的 \(A\dfrac{f_n}{g_n}+B\dfrac{f_{n+1}}{g_n}\) 可以在模 \(G\times c\) 意义下进行运算,此时保证了除掉 \(G\) 就得到了模 \(c\) 的结果

Code Display
int mod,n,a,b,c,d;
inline int add(int x,int y,int Mod=mod){return x+y>=Mod?x+y-Mod:x+y;}
inline int del(int x,int y,int Mod=mod){return x-y<0?x-y+Mod:x-y;}
inline int mul(int x,int y,int Mod=mod){return x*y-x*y/Mod*Mod;}
inline void ckadd(int &x,int y,int Mod=mod){x=x+y>=Mod?x+y-Mod:x+y;}
inline void ckdel(int &x,int y,int Mod=mod){x=x-y<0?x-y+Mod:x-y;}
inline void ckmul(int &x,int y,int Mod=mod){x=x*y-x*y/Mod*Mod;}
inline int ksm(int x,int y,int Mod=mod){int res=1; for(;y;y>>=1,ckmul(x,x,Mod)) if(y&1) ckmul(res,x,Mod); return res;}
inline void approx(int val,int Mod=mod,int lim=1e5){int x=val,y=Mod,a=1,b=0; while(x>lim){swap(x,y); swap(a,b); a-=x/y*b; x%=y;} cout<>=1;
        }
        return res;
    }
};
inline int Get_reminder(int n,int Mod){
    Matrix cur(Mod);
    cur.a[0][0]=31%Mod;
    cur.a[0][1]=3%Mod;
    cur.a[1][0]=36%Mod;
    cur.a[1][1]=4%Mod;
    cur=cur.qpow((n-1)/2);
    int ev=add(cur.a[0][1],cur.a[1][1],Mod);
    int od=add(cur.a[1][0],cur.a[0][0],Mod);
    if(n&1) return od;
    else return (4*ev+3*od)%Mod;
}
signed main(){
    freopen("c.in","r",stdin); freopen("c.out","w",stdout);
    int T=read(); while(T--){
        n=read(); mod=read(); 
        a=read(); b=read(); c=read(); d=read();
        pair A={a,b};
        pair B={c,d};
        if(!b) swap(A,B);
        while(A.sec&&B.sec){
            int t=A.sec/B.sec;
            A.sec%=B.sec; A.fir-=B.fir*t;
            swap(A,B);
        }
        a=A.fir; b=A.sec; c=B.fir; d=B.sec;
        if(c<0) c=-c;
        if(a<0) a=-a,b=-b;
        if(b==0){
            Matrix now(mod);
            now.a[0][0]=9%mod;
            now.a[0][1]=1%mod;
            now.a[1][0]=12%mod;
            now=now.qpow(n-1);
            print(mul(__gcd(a,c),add(now.a[0][0],now.a[1][0])));
            continue;
        }
        if(c==0){
            Matrix now(mod);
            now.a[0][0]=9%mod;
            now.a[0][1]=1%mod;
            now.a[1][0]=12%mod;
            now=now.qpow(n-1);
            int fcur=add(now.a[0][0],now.a[1][0]);
            int flst=add(now.a[0][1],now.a[1][1]);
            int fnxt=(fcur*9+flst*12)%mod;
            int ans=a*fcur+b*fnxt;
            print((ans%mod+mod)%mod);
            continue;
        }
        int G=__gcd(Get_reminder(n,abs(b)),abs(b));
        int tmod=G*c;
        int vcur=Get_reminder(n,tmod);
        int vnxt=Get_reminder(n+1,tmod);
        if(n&1) ckmul(vnxt,3,tmod);
        int val=((a*vcur+b*vnxt)%tmod+tmod)%tmod;
        val=__gcd(val/G,c);
        print(val*ksm(3,n/2)%mod*G%mod);
    }
    return 0;
}

相关