• luoguP3281 [SCOI2013]数数


    传送门

    抄的llj的代码

    还有点问题没弄懂,先码着

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #define For(i,a,b) for(int i=(a);i<=(b);i++)
    #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    const int N=2e5+7,mod=20130427;
    typedef long long LL;
    typedef double db;
    using namespace std;
    LL power[N],sum[N],S[N],f[N][2],ans1,ans2,p[N],q[N],a[N],b[N],B,n,m;;
    
    template<typename T>void read(T &x)  {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    void jian(LL &n) {
        if(a[1]) a[1]--;
        else {
            a[1]=B-1;
            For(i,2,n) {
                a[i]--;
                if(a[i]>=0) break;
                a[i]=B-1;
            }
        }
        while(n&&!a[n]) n--;
    }
    
    void pre(int len) {
        power[0]=1; sum[0]=1;
        For(i,1,len) power[i]=power[i-1]*B%mod;
        For(i,1,len) sum[i]=(sum[i-1]+power[i])%mod;
    }
    
    void calc(LL s[],int n,LL& ans) {
        memset(f,0,sizeof(f));
        p[0]=q[n+1]=0;
        For(i,1,n) p[i]=(p[i-1]+s[i]*power[i-1]%mod)%mod;
        Rep(i,n,1) q[i]=(q[i+1]*B%mod+s[i])%mod;
        For(i,1,n) {
            LL tp=B*(B-1)/2%mod;
            f[i][0]=f[i-1][0]*B%mod+tp*sum[i-1]%mod*power[i-1]%mod;
            tp=s[i]*(s[i]-1)/2%mod;
            f[i][1]=(tp*sum[i-1]%mod*power[i-1]%mod+s[i]*f[i-1][0]%mod+f[i-1][1]+s[i]*sum[i-1]%mod*(p[i-1]+1)%mod)%mod;
            ans=(ans+(q[i+1]>1?(q[i+1]-1):0LL)*f[i][0]%mod+f[i][1])%mod;
        }
    } 
    
    int main() {
    #ifdef DEBUG
        freopen(".in","r",stdin);
        freopen(".out","w",stdout);
    #endif
        read(B);
        read(n); For(i,1,n) read(a[n-i+1]);
        read(m); For(i,1,m) read(b[m-i+1]); jian(n);
        pre(200000);
        calc(a,n,ans1); 
        calc(b,m,ans2); 
        printf("%lld
    ",(ans2-ans1+mod)%mod);
        return 0;
    }
    /*
    55
    5 54 12 6 27 14
    7 45 11 25 48 7 45 52
    */
    View Code

    -------------------------------------更新题解---------------------------------------------------

    设$f[i][0/1]$表示以从右往左第$i$个数字开头的所有前缀和的和

    $0$表示$i$前面没有达到上限,$1$表示$i$以前都达到上限

    $power[i]表示B^i,sum[i]为power的前缀和$

    $f[i][0]=f[i-1][0]*B+B*(B-1)/2*sum[i-1]$

    $f[i][0]=f[i-1][0]*B(这一位B种选法)+B*(B-1)/2(这一位B种选法的和)*sum[i-1](这一位对每个前缀的贡献)$

    $q[i]为左数第1到第n-i+1个的上限值,p[i]为右数第1至第i的上限值$

    $s[i]为右数第i个数的上限值$

    $f[i][0]=s[i]*(s[i]-1)/2*sum[i-1]*power[i-1]+s[i]*f[i-1][0]+f[i-1][1]+s[i]*sum[i-1]*q[i+1]-q[i]$

    $f[i][1]=s[i]*(s[i]-1)/2*sum[i-1]*power[i-1]$
    这一位取不超过0~s[i]-1,即不超过上限,后面就有power[i-1]种情况,每种这一位的贡献都是作为每个前缀的贡献和。

    $+s[i]*f[i-1][0]$
    这一位取0~s[i]-1的s[i]中情况下,后面的位对前缀和的贡献是f[i-1][0](未到达上限)

    $+f[i-1][1]$
    这一位取s[i]这一种情况下,后面的位对前缀和的贡献是f[i-1][1](达到上限)

    $+s[i]*sum[i-1]*q[i+1]$
    这一位取s[i]这一种情况下,这一位对前缀和的贡献

    $-f[i-1][0]$计算f时考虑了前导0,完整的串不能包含前导0,减去前面取0(一种情况),这一位也取0的方案

  • 相关阅读:
    Altium Designer如何导出SMT贴片机用的坐标文件
    STM8S003设计注意事项
    Keil4打开KEIL5未响应卡死的问题
    STM32 adc 多通道采集相互串扰问题解决
    STM32 RS485 和串口 只能接收不能发送问题解决
    AD中元器件报警的处理——器件高度报警
    QT乱码解决办法《转》
    STM32下载失败,st-link v2 在线下载sw模式检测不到
    docker部署普罗米修斯监控
    进程管理常用命令
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8666645.html
Copyright © 2020-2023  润新知