zoukankan      html  css  js  c++  java
  • 题解 P6435 【「EZEC-1」数列】

    传送门

    久违地来一波题解,来一个数学角度推式子的方法


    【分析】

    记第 (k) 次合并后的第 (i) 个数为 (F_{k,i})

    根据题意,所求即为 (ans=F_{n-1,n}) ,且有:

    (F_{k+1,n}=aF_{k,n}+bF_{k,n+1}+c,F_{0,i}=i)

    形式上,我们设 (exists dwedge F_{k+1,i}+d=a(F_{k,i}+d)+b(F_{k,i+1}+d))

    则不难换算出 ((a+b-1)d=c)

    注意,只是形式上这样设, (d) 可能本身不存在

    (G_{k,i}=F_{k,i}+d) 则得到: (G_{k+1,i}=aG_{k,i}+bG_{k,i+1})

    考虑 (G) 之间的转移,发现与杨辉三角类似,故考虑每个 (G_{0,i}) 的贡献,很容易得到:

    (displaystyle G_{n-1,n}=sum_{i=1}^ndbinom{n-1}{i-1}a^{(n-1)-(i-1)}b^{i-1}G_{0,i})

    代回 (G_{k,i}=F_{k,i}+d,F_{0,i}=i,ans=F_{n-1,n}) ,换元 (i=i-1)

    (displaystyle ans=sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}b^i(i+1+d)-d)

    (d) 展开后得到:

    (displaystyle ans=sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}b^icdot (i+1)+d[sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}b^i-1])

    后半部分是个很显然的二项式定理,求和得到 ((a+b)^{n-1})

    再代回 ((a+b-1)d=c) 得到:(displaystyle ans=sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}b^i(i+1)+ccdot {(a+b)^{n-1}-1over (a+b)-1})

    接着,我们构造函数,设 (displaystyle f(x)=sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}x^{i+1}=x(a+x)^{n-1})

    因此 (displaystyle { ext dover ext dx}f(x)=sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}x^icdot (i+1)={ ext dover ext dx}[x(a+x)^{n-1}]=(a+x)^{n-1}+xcdot (a+x)^{n-2}cdot (n-1))

    整理得到: (displaystyle sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}x^icdot (i+1)=(a+x)^{n-2}cdot (a+nx))

    所以得到 (displaystyle sum_{i=0}^{n-1}dbinom{n-1}ia^{(n-1)-i}b^icdot (i+1)=(a+b)^{n-2}cdot (a+nb))

    最后我们得到: (ans=(a+b)^{n-2}cdot (a+nb)+ccdot {1-(a+b)^{n-1}over 1-(a+b)})


    法一:

    对于前半部分,快速幂 (O(log n)) 可直接算出;而后半部分,可能不存在 (1-(a+b)) 的逆元,不能直接求解

    考虑到其形式上为等比数列求和式,展开为: (1+(a+b)+(a+b)^2+cdots +(a+b)^{n-2})

    (sumq(q,n)=1+q+q^2+cdots +q^n)

    则取一个数 (m) ,使得 (1+q+q^2+cdots +q^n=(1+q+q^2+cdots +q^m)(1+q^{m+1}+q^{2(m+1)+cdots}+q^{lfloor{n-mover m+1} floorcdot (m+1)})+q^{m+lfloor{n-mover m+1} floorcdot (m+1)+1}(1+q+cdots))

    因此 (sumq(q,n)=sumq(q,m)cdot sumq(q^{m+1},lfloor{n-mover m+1} floor)+q^{m+lfloor{n-mover m+1} floorcdot (m+1)+1}cdot sumq(q,n-m-lfloor{n-mover m+1} floorcdot (m+1)-1)) ,可以递归求解

    通过估算,大概 (m=sqrt n) 时最优


    现分析求 (sumq(q,n)) 的复杂度:

    (T(n)approx T(m)+T(m)+T(n-m^2)+log m+log nleq 3T(n^{1over 2})+{3over 2}log n)

    (k=log n)(T(k)=3T({kover 2})+{3over 2}k)

    再记 (2^a=k)(T(a)=3T(a-1)+{3over 2}cdot 2^a)

    解递推方程得到 (T(a)=3^a+o(3^a)=O(3^a))

    代回得 (3^a=2^{alog_2 3}=k^{log_2 3}=log^{log_2 3} n)

    因此 (T(n)=O(log^{log_2 3} n)approx O(log^{1.6} n))


    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,a,b,c,p,ans=1;
    inline __int128 fpow(__int128 a,ll x) { ll ans=1; for(;x;x>>=1,a=a*a%p) if(x&1) ans=ans*a%p; return ans; }
    inline __int128 sumq(__int128 q,ll n){
        if(n==0) return 1%p;
        if(n==1) return (q+1)%p;
        ll m=sqrt(n),tmp=(n-m)/(m+1)*(m+1)+m;
        __int128 res=sumq(q,m)*sumq( fpow(q,m+1) , (n-m)/(m+1) )%p;
        if(tmp<n) res+=fpow(q,tmp+1)*sumq(q,n-tmp-1)%p;
        return (res%p+p)%p;
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        cin>>n>>a>>b>>c>>p;
        if(n>1) ans=fpow(a+b,n-2)*(a+(__int128)n*b%p)%p+c*sumq(a+b,n-2)%p;
        ans=(ans%p+p)%p;
        cout<<ans;
        cout.flush();
        return 0;
    }
    

    法二:

    想了想,好像没那么复杂

    考虑到 (a,bgeq 1),所以 (a+b>1) 一定成立

    因此,前半部分同样快速幂直接跑

    后半部分为形如 ({q^n-1over q-1},q>1) 的形式

    ({q^n-1over q-1}mod p=t)

    ({q^n-1over q-1}-kp=t)

    移项得到 (q^n-kp(q-1)=t(q-1)+1)

    因此 (q^nmod p(q-1)=t(q-1)+1)

    由于我们所求为 (t) ,因此得出:

    (t={q^nmod p(q-1)-1over q-1})

    我们直接把 (q) 在模 (p(q-1)) 的意义下跑快速幂,结果直接进行这个处理,就能得到我们索要的结果了

    其中,(p(q-1)leq 10^{14}cdot (10^9+10^9)=2 imes 10^{23}) ,要使用 __int128

    由于数值过大,甚至对 __int128 写拆位的快速乘都不行,因此只能龟速乘

    时间复杂度为 (O(log^2 n)) ,但由于没有递归,运行速率好像反而比法一快


    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,a,b,c,p,ans=1;
    inline __int128 fpow(__int128 a,__int128 x,__int128 m) { __int128 ans=1; for(;x;x>>=1,a=a*a%m) if(x&1) ans=ans*a%m; return ans; }
    //不用龟速乘的快速幂
    inline __int128 fmul(__int128 a,__int128 x,__int128 m) { __int128 ans=0; for(;x;x>>=1,a=(a+a)%m) if(x&1) ans=(a+ans)%m; return ans; }
    inline __int128 fpoww(__int128 a,__int128 x,__int128 m) { __int128 ans=1; for(;x;x>>=1,a=fmul(a,a,m)) if(x&1) ans=fmul(a,ans,m); return ans; }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        cin>>n>>a>>b>>c>>p;
        if(n>1) ans=fpow(a+b,n-2,p)*(a+(__int128)n*b%p)%p+(fpoww(a+b,n-1,(__int128)p*(a+b-1))-1)/(a+b-1)*c%p;
        ans=(ans%p+p)%p;
        cout<<ans;
        cout.flush();
        return 0;
    }
    

    虽然必须用龟速乘,但我们可以对龟速乘搞事情:

    由于 (127-log_2 (2 imes 10^{23})approx49)

    所以我们龟速乘可以48位、48位地算,这样就只要3次计算

    (稍微卡了一下常数)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,a,b,c,p,ans=1;
    inline ll fpow(__int128 a,ll x,ll m) { ll ans=1; for(;x;x>>=1,a=a*a%m) if(x&1) ans=ans*a%m; return ans; }
    //不用龟速乘的快速幂
    inline __int128 fmul(__int128 a,__int128 x,__int128 m) { __int128 ans=0; for(;x;x>>=48,a=(a<<48)%m) ans=(a*(x&(1ll<<48)-1)+ans)%m; return ans; }
    inline __int128 fpoww(__int128 a,__int128 x,__int128 m) { __int128 ans=1; for(;x;x>>=1,a=fmul(a,a,m)) if(x&1) ans=fmul(a,ans,m); return ans; }
    int main(){
        cin>>n>>a>>b>>c>>p;
        if(n>1) ans=fpow(a+b,n-2,p)*(a+(__int128)n*b%p)%p + (fpoww(a+b,n-1,(__int128)p*(a+b-1))-1)/(a+b-1)*c%p +p;
        cout<<ans%p;
        return 0;
    }
    

    目前好像是榜一

    开了 o2

    不开 o2

  • 相关阅读:
    Spring IOC注入接口多实现解决
    Spring Security 学习总结
    Spring Boot自动配置与Spring 条件化配置
    1403. Minimum Subsequence in Non-Increasing Order
    1457. Pseudo-Palindromic Paths in a Binary Tree
    1368. Minimum Cost to Make at Least One Valid Path in a Grid
    1456. Maximum Number of Vowels in a Substring of Given Length
    1455. Check If a Word Occurs As a Prefix of Any Word in a Sentence
    1472. Design Browser History
    1471. The k Strongest Values in an Array
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14348490.html
Copyright © 2011-2022 走看看