zoukankan      html  css  js  c++  java
  • T137223 节能主义

    设平均数为$x$,那么有差值数组$b_i=a_i-x$。

    考虑用类似于均分纸牌的方法来解决本题,从左到右依次考虑每堆书,直接乘上预处理好的组合数,然后清零$b_i$。

    在实际操作中,将冗余的操作忽略,肯定是由大书堆向小书堆的方向移动,并且每对相邻位置的移动方向是确定的。

    所以我们可以一遍扫过去,如果当前这堆书多了,就往后移;要是不够,就从后面拿过来。每次使当前位置达到平均值,并且将富余/缺口推给下一个位置。

    要是后面也不够填补当前位置的缺口呢?我们可以想到,在实际操作中,书一定会先从更后面传递过来,而到了恰好下一个位置时,下一个位置多出来的书一定会是刚好填补当前位置的缺口的。所以在这一步计算方案数时,就可以直接使用“下个位置的书总数是平均数加上当前位置的缺口量”这样的状态。不过“推缺口”操作还是一样的。

    具体地说,考虑$b_i$:

    1. 若$b_i>0$,则将第$i$堆中超出的所有书移到第$i+1$堆,方案数为$dbinom{a_i}{b_i}$。
    2. 若$b_i<0$,则将第$i+1$堆中取出$-b_i$移到第$i$堆。若第$i+1$堆当前足够多,方案数为$dbinom{a_{i+1}}{-b_i}$;若不够多,方案数为$dbinom{x-b_i}{-b_i}$。

    核心的贪心思想如上。接下来解决组合数的问题。

    当$kle 4 imes 10^3$时,可以使用杨辉三角预处理组合数,时间复杂度为$O(k^2)-O(Tn)$;当$kle 10^6$时,预处理阶乘及其乘法逆元,时间复杂度$O(k)-O(Tn)$。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<ctime>
    #define IL inline
    #define RG register
    using namespace std;
    typedef long long LL;
    const int N=1e3;
    const int M=1e6;
    #define RI RG int
    #define RC RG char
    #define RL RG LL
    const LL mod=998244353;
    
    IL void qr(RI &x){
        x=0;    RC ch=getchar();
        while(!isdigit(ch))    ch=getchar();
        for(;isdigit(ch);ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    }
    
    IL void qw(RL &x,RC ch){
        RI k=0,s[23];
        if(x==0)    s[k=1]=0;
        else     for(;x;x/=10)    s[++k]=x%10;
        for(;k;k--)    putchar(s[k]+'0');
        putchar(ch);
    }
    
        int T,n;
        int a[N+3],b[N+3];
        LL jc[M+3],jv[M+3];
    
    IL LL qpow(RL a,RL b){
        LL ans=1;
        for(a%=mod;b;a=a*a%mod,b>>=1)
        if(b&1)    ans=ans*a%mod;
        return ans;
    }
    
    IL LL C(RI n,RI m){
        RL x=jc[n],y=(jv[m]*jv[n-m])%mod;
        return x*y%mod;
    }
    
    IL void init(){
        jc[0]=jv[0]=1;
        for(RI i=1;i<=M;i++)
            jc[i]=(jc[i-1]*i)%mod;
        jv[M]=qpow(jc[M],mod-2);
        for(RI i=M;i>=2;i--)
            jv[i-1]=(jv[i]*i)%mod;
        
    }
    
    IL void sol(){
        qr(n);
        for(RI i=1;i<=n;i++)
            qr(a[i]);
            
        RI sum=0;
        for(RI i=1;i<=n;i++)
            sum+=a[i];
        RI ave=sum/n;
        for(RI i=1;i<=n;i++)
            b[i]=a[i]-sum/n;
        
        RL ans=1;
        for(RI i=1;i<n;i++)
        if(b[i]>0){
            ans=ans*C(a[i],b[i])%mod;
            a[i+1]+=b[i];
            b[i+1]+=b[i];
            a[i]-=b[i];
            b[i]=0;
            
        }
        else 
        if(b[i]<0){
            ans=ans*C(max(ave-b[i],a[i+1]),-b[i])%mod;
            a[i+1]+=b[i];
            b[i+1]+=b[i];
            a[i]-=b[i];
            b[i]=0;
            
        }
        qw(ans,'
    ');
        
    }
    
    int main(){
        init();
        qr(T);
        while(T--)
            sol();
        
        return 0;
        
    }
    View Code
  • 相关阅读:
    C++类构造函数初始化列表(转)
    Linux可重入函数和线程安全的区别与联系(转)
    Splinter自动登录
    VBA添加下拉菜单
    批处理自动备份并生成日志文件
    VBA 格式化excel数据表 (数据分列)
    Python 调用outlook发送邮件(转 )
    Node.js 文件操作
    Node.js express模块 http服务
    将ejs模板文件的后缀换成html
  • 原文地址:https://www.cnblogs.com/Hansue/p/13187861.html
Copyright © 2011-2022 走看看