zoukankan      html  css  js  c++  java
  • 【题解】洛谷 P7468 [NOI Online 2021 提高组] 愤怒的小N【自然数幂和 结论题】

    题目链接

    题意

    定义串 (A_0= exttt{a})(A_i=A_{i-1}+overline{A_{i-1}})(其中上划线代表 a b 互换),考虑串 (A_infty[0..n-1])。给定 (k-1) 次多项式 (f),求 (sum_{i=0}^{n-1}[A_infty[i]= exttt{b}]f(i))(nleq 2^{500000})(kleq 500)

    题解

    我们首先考虑 (O(k^2log n)) 的做法:我们维护多项式 (F_{i, exttt{a}/ exttt{b}}(x)) 代表把字符串 (A_i) 平移到 (x) 处后,( exttt{a}/ exttt{b}) 的贡献。

    我们有 (F_{i, exttt{a}}(x)=F_{i-1, exttt{a}}(x)+F_{i-1, exttt{b}}(x+2^{i-1}))(F_{i, exttt{b}}) 同理),处理系数平移需要 (O(k^2))(二项式定理展开),一共要递推到 (F_{log n, exttt{a}/ exttt{b}})

    如果你在调试时输出了多项式,你可能会发现在 (igeq k) 时,(F_{i, exttt{a}}=F_{i, exttt{b}})。证明可以参见官方题解。(考试时我输出了调试信息,但是没发现结论)

    知道这个结论后,我们可以只处理到 (F_{k-1, exttt{a}/ exttt{b}}),剩下的部分借助自然数幂和计算。复杂度 (O(k^3+log n))

    #include<bits/stdc++.h>
    using namespace std;
    int getint(){
        int ans=0;
        char c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c)){
            ans=ans*10+c-'0';
            c=getchar();
        }
        return ans;
    }
    const int K=503,N=500010,mod=1e9+7;
    int f[2][K],g[2][K];
    int c[K][K];
    char s[N];int n;
    
    int p2[N];
    int p[N],q[N];
    
    int sp[N];
    int qpow(int x,int y){
        int ans=1;
        while(y){
            if(y&1)ans=ans*1ll*x%mod;
            x=x*1ll*x%mod;
            y>>=1;
        }
        return ans;
    }
    int main(){
        freopen("angry.in","r",stdin);
        freopen("angry.out","w",stdout);
        scanf("%s",s+1);
        n=strlen(s+1);
        int k=getint();
        if(n<k){
            for(int i=n;i;i--)s[k-n+i]=s[i];
            for(int i=1;i<=k-n;i++)s[i]='0';
            n=k;
        }
        for(int i=0;i<k;i++)f[0][i]=getint();
        for(int i=c[0][0]=1;i<=k;i++)
            for(int j=c[i][0]=1;j<=k;j++)
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        p2[0]=1;for(int i=1;i<=n;i++)p2[i]=p2[i-1]<<1,p2[i]>=mod&&(p2[i]-=mod);
        for(int i=1;i<=n;i++){
            q[n-i]=q[n-i+1]^(s[i]-'0');
            p[n-i]=(p[n-i+1]+(s[i]-'0')*p2[n-i])%mod;
        }
    
        int ans=0;
    
        int m=p[0];
        // cerr<<"> "<<m<<endl;
        sp[0]=m;
        for(int i=1;i<k;i++){
            sp[i]=qpow(m,i+1);
            for(int j=0;j<i;j++)
                sp[i]=(sp[i]-c[i+1][j]*1ll*sp[j]%mod+mod)%mod;
            sp[i]=sp[i]*1ll*qpow(i+1,mod-2)%mod;
            // cerr<<"> "<<sp[i]<<endl;
        }
        for(int i=0;i<k;i++)ans=(ans+f[0][i]*1ll*sp[i])%mod;
    
        for(int i=0;i<k;i++){
            // for(int i=0;i<k;i++)cerr<<">"<<f[0][i];cerr<<endl;
            // for(int i=0;i<k;i++)cerr<<">"<<f[1][i];cerr<<endl;cerr<<endl;
            int q=::q[i],p=::p[i+1];
            if(s[n-i]-'0'){
                int v=0;
                for(int j=0;j<k;j++)
                    v=(v*1ll*p+f[q][k-j-1])%mod;
                ans=(ans+v)%mod;
                v=0;
                for(int j=0;j<k;j++)
                    v=(v*1ll*p+f[q^1][k-j-1])%mod;
                ans=(ans+mod-v)%mod;
            }
    
            memcpy(g,f,sizeof(g));
            int e=p2[i];
            for(int j=0;j<k;j++){
                int pe=1;
                for(int l=j;l>=0;l--,pe=pe*1ll*e%mod){
                    int t=pe*1ll*c[j][l]%mod;
                    g[1][l]=(g[1][l]+f[0][j]*1ll*t)%mod;
                    g[0][l]=(g[0][l]+f[1][j]*1ll*t)%mod;
                }
            }
            memcpy(f,g,sizeof(f));
        }
    
        ans=(mod+1ll)/2*ans%mod;
    
        cout<<ans;
    }
    
    
    知识共享许可协议
    若文章内无特别说明,公开文章采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
  • 相关阅读:
    Linux 下动态查找磁盘数量方法
    Laravel 学习 .env文件 getenv 获得环境变量的值
    win10系统怎样手动安装cab更新补丁
    TP框架中模糊查询实现
    PHP函数之HTMLSPECIALCHARS_DECODE
    Tp框架—方法中处理数据
    TP框架I方法详解
    鼠标经过图像改变实现
    TP视图命名规则之一
    Json_decode:详解
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/14586269.html
Copyright © 2011-2022 走看看