• 【考试总结】20220411


    争辩

    \(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;
    }
    

  • 相关阅读:
    查看Eclipse版本号的方法
    设置Eclipse的字体风格方式
    又遇两个小异常
    我所推崇的三种心态
    关于javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in &lt;forEach&gt;
    Http请求中Content-Type讲解
    ftp实现文件上传(下载)
    解析html文档的java库及范例
    xslt循环转换子元素
    XPath学习:轴(1)——child
  • 原文地址:https://www.cnblogs.com/yspm/p/16131592.html
Copyright © 2020-2023  润新知