• 2019牛客暑期多校训练营(第二场)


    参考于:
    https://www.luogu.org/problemnew/solution/P4723 shadowice1984 (太难)
    https://www.cnblogs.com/zhgyki/p/9671855.html (玄学)

    居然还有解释:
    https://www.cnblogs.com/zhouzhendong/p/Berlekamp-Massey.html

    线性递推BM算法,把前面的8~10项push进去?
    下面是板子,求第n项调用参数是n-1。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    #define pb push_back
    #define mp make_pair
    #define all(x) (x).begin(),(x).end()
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    typedef vector<int> VI;
    typedef long long ll;
    typedef pair<int,int> PII;
    const ll mod=1000000007;
    ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    // head
    
    ll n;
    namespace linear_seq {
        const int N=10010;
        ll res[N],base[N],_c[N],_md[N];
    
        vector<int> Md;
        void mul(ll *a,ll *b,int k) {
            rep(i,0,k+k) _c[i]=0;
            rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
            for (int i=k+k-1;i>=k;i--) if (_c[i])
                rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
            rep(i,0,k) a[i]=_c[i];
        }
        int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
            ll ans=0,pnt=0;
            int k=SZ(a);
            assert(SZ(a)==SZ(b));
            rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
            Md.clear();
            rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
            rep(i,0,k) res[i]=base[i]=0;
            res[0]=1;
            while ((1ll<<pnt)<=n) pnt++;
            for (int p=pnt;p>=0;p--) {
                mul(res,res,k);
                if ((n>>p)&1) {
                    for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
                    rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
                }
            }
            rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
            if (ans<0) ans+=mod;
            return ans;
        }
        VI BM(VI s) {
            VI C(1,1),B(1,1);
            int L=0,m=1,b=1;
            rep(n,0,SZ(s)) {
                ll d=0;
                rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
                if (d==0) ++m;
                else if (2*L<=n) {
                    VI T=C;
                    ll c=mod-d*powmod(b,mod-2)%mod;
                    while (SZ(C)<SZ(B)+m) C.pb(0);
                    rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                    L=n+1-L; B=T; b=d; m=1;
                } else {
                    ll c=mod-d*powmod(b,mod-2)%mod;
                    while (SZ(C)<SZ(B)+m) C.pb(0);
                    rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                    ++m;
                }
            }
            return C;
        }
        int gao(VI a,ll n) {
            VI c=BM(a);
            c.erase(c.begin());
            rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
            return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
        }
    };
    
    int main() {
        /*push_back 进去前 8~10 项左右、最后调用 gao 得第 n 项*/
        vector<int>v;
        v.push_back(3);
        v.push_back(9);
        v.push_back(20);
        v.push_back(46);
        v.push_back(106);
        v.push_back(244);
        v.push_back(560);
        v.push_back(1286);
        v.push_back(2956);
        v.push_back(6794);
        int nCase;
        scanf("%d", &nCase);
        while(nCase--){
            scanf("%lld", &n);
            printf("%lld
    ",1LL * linear_seq::gao(v,n-1) % mod);
        }
    }
    

    仿照上面的思路瞎搞通过。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for (int i=a;i<n;i++)
    typedef vector<int> vi;
    typedef long long ll;
    const ll mod=1000000007;
    
    ll qpow(ll x,ll n) {
        ll res=1;
        for(; n; x=x*x%mod,n>>=1)
            if(n&1)
                res=res*x%mod;
        return res;
    }
    
    namespace Linear_Recurrence {
    
    //空间无所谓,开大一点
    const int N=10010;
    ll res[N],base[N],c[N],md[N];
    
    int umd[N],sizumd;
    void mul(ll *a,ll *b,int k) {
        rep(i,0,k+k) c[i]=0;
        rep(i,0,k) if (a[i])
            rep(j,0,k) c[i+j]=(c[i+j]+a[i]*b[j])%mod;
    
        for (int i=k+k-1; i>=k; i--)
            if (c[i])
                rep(j,0,sizumd) c[i-k+umd[j]]=(c[i-k+umd[j]]-c[i]*md[umd[j]])%mod;
    
        rep(i,0,k) a[i]=c[i];
    }
    
    int solve(ll n,vi a,vi b) {
        //a是系数向量,b是初值向量
        //递推公式形如b[n+1]=a[0]*b[n]+a[1]*b[n-1]+...
        ll ans=0,pnt=0;
        int k=a.size();
        rep(i,0,k) md[k-1-i]=-a[i];
        md[k]=1;
        sizumd=0;
        rep(i,0,k) {
            if (md[i]!=0)
                umd[sizumd++]=i;
        }
        rep(i,0,k) res[i]=0,base[i]=0;
        res[0]=1;
    
        while ((1ll<<pnt)<=n)
            pnt++;
        for (int p=pnt; p>=0; p--) {
            mul(res,res,k);
            if ((n>>p)&1) {
                for (int i=k-1; i>=0; i--)
                    res[i+1]=res[i];
                res[0]=0;
                rep(j,0,sizumd) res[umd[j]]=(res[umd[j]]-res[k]*md[umd[j]])%mod;
            }
        }
        rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
        if (ans<0)
            ans+=mod;
        return ans;
    }
    vi BM(vi s) {
        vi C(1,1),B(1,1);
        int L=0,m=1,b=1;
        int sizs=s.size();
        rep(n,0,sizs) {
            ll d=0;
            rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
            if (d==0)
                ++m;
            else if (2*L<=n) {
                vi T=C;
                int sizB=B.size();
                while (C.size()<sizB+m)
                    C.push_back(0);
                ll t=mod-d*qpow(b,mod-2)%mod;
                rep(i,0,sizB) C[i+m]=(C[i+m]+t*B[i])%mod;
                L=n+1-L,B=T,b=d,m=1;
            } else {
                int sizB=B.size();
                while (C.size()<sizB+m)
                    C.push_back(0);
                ll t=mod-d*qpow(b,mod-2)%mod;
                rep(i,0,sizB) C[i+m]=(C[i+m]+t*B[i])%mod;
                ++m;
            }
        }
        return C;
    }
    int gao(vi A,ll n) {
        vi C=BM(A);
        C.erase(C.begin());
        int sizC=C.size();
        rep(i,0,sizC) C[i]=(mod-C[i])%mod;
        return solve(n,C,vi(A.begin(),A.begin()+sizC));
    }
    };
    
    ll dp[3005];
    
    ll solve(int k,ll n) {
        ll invk=qpow(k,mod-2);
        dp[0]=1;
        //至少取2倍以上
        int c=k*2;
        for(int i=1; i<=c+1; i++) {
            dp[i]=0;
            for(int j=max(0,i-k); j<=i-1; j++) {
                dp[i]+=dp[j];
            }
            dp[i]=(dp[i]%mod)*invk%mod;
        }
        vi v;
        for(int i=0; i<=c+1; i++)
            v.push_back((int)dp[i]);
        //从0开始,到n,这里其实是第n+1项
        return Linear_Recurrence::gao(v,n);
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in","r",stdin);
    #endif // Yinku
        int t,k;
        ll n;
        scanf("%d", &t);
        while(t--) {
            scanf("%d%lld", &k,&n);
            if(n==-1)
                printf("%lld
    ",2ll*qpow(k+1,mod-2)%mod);
            else
                printf("%lld
    ",solve(k,n));
        }
    }
    

    好像前2K项比较保险,前K项就WA了,前1.5K项也WA了,临界值是多少呢?反正大概取2~3倍递推可能就够了吧。

  • 相关阅读:
    Spark API 之 map、mapPartitions、mapValues、flatMap、flatMapValues详解
    大三寒假生活9
    大三寒假生活8
    大三寒假生活7
    MySQL SQL DML (数据操作语言)
    MySQL JOIN
    Python 可执行对象
    Python __slots__
    Python tempfile (临时文件)
    Python 文件操作
  • 原文地址:https://www.cnblogs.com/Yinku/p/11220848.html
Copyright © 2020-2023  润新知