1. 程式人生 > 其它 >【考試總結】2022-04-11

【考試總結】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<n;++i){
        for(int j=1;j<=i;++j){
            ckadd(f[cur^1][j][1],mul(f[cur][j][0],M[i-1][i]));
            ckadd(f[cur^1][i][1],mul(f[cur][j][1],M[i-1][j]));
            ckadd(f[cur^1][i][0],mul(f[cur][j][0],M[i-1][j]));
            ckadd(f[cur^1][j][0],mul(f[cur][j][1],M[i-1][i]));
            f[cur][j][1]=f[cur][j][0]=0;
        }
        cur^=1;
    }
    int ans=0;
    rep(i,1,n){
        for(int j=0;j<=1;++j) if(f[cur][i][j]){
            int coef=mul(M[n-j][i],M[n-(!j)][n]);
            ckadd(ans,mul(coef,f[cur][i][j]));
        }
    }
    printf("%lld %lld\n",del(Mult,ans),ans);
    return 0;
}

分解

對著式子新增最小因子可以發現 \(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<int,int> solve(int n,int id){
    if(pri[id]>n||id>cnt) return {0,0};
    pair<int,int> 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<int,int> 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<<x<<"/"<<a<<endl; return ;}

struct Matrix{
    int a[2][2],mod; 
    Matrix(int Mod){memset(a,0,sizeof(a)); mod=Mod; return ;}
    Matrix operator *(const Matrix &b)const{
        Matrix res(mod);
        res.a[0][0]=add(mul(a[0][1],b.a[1][0],mod),mul(a[0][0],b.a[0][0],mod),mod);
        res.a[1][1]=add(mul(a[1][1],b.a[1][1],mod),mul(a[1][0],b.a[0][1],mod),mod);
        res.a[1][0]=add(mul(a[1][1],b.a[1][0],mod),mul(a[1][0],b.a[0][0],mod),mod);
        res.a[0][1]=add(mul(a[0][1],b.a[1][1],mod),mul(a[0][0],b.a[0][1],mod),mod);
        return res;
    }
    Matrix qpow(int y){
        Matrix res(mod),bas=*this;
        res.a[1][1]=res.a[0][0]=1%mod;
        while(y){
            if(y&1) res=res*bas;
            bas=bas*bas;   
            y>>=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<int,int> A={a,b};
        pair<int,int> 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;
}