• atcoder ARC104 D Multiset Mean


    ARC104 D

    传送门

    题意:给你三个数字:N,K,M(N,K<=100)。对于[1,N]内的每一个数x,你需要解决以下问题:对于[1,N]内的每一个数字,你最多取K个,这样组成的数组的平均值是x。

    首先我们需要一个转化:对于其中的一个问题,将[1,N]中的数字写成 -x,-(x-1),-(x-2),... , -1, 0, 1, 2, ... ,y-1, y。现在将大于0和小于0的数字分成两个部分。在这两个部分中,每一个数字最多选择K次。如果使得它们的和一样,那就跟原问题是等价的。这给我们一个相当naive的dp:

    [dp[i][j]表示的是,考虑[1, i]中的数字,每一个最多选择K个,和为j的方案数。转移的时候,要用一个前缀和去维护,这使得转移更快。 ]

    最终答案是,相同的值的方案数*(K+1)-1。其中K+1的贡献其实是你要考虑x的个数,0-K都是可行的。-1的意义是,去掉空集。

    如果你对每一个x,都去跑一遍这个dp,然后会发现复杂度是O(n5),直接gg。事实上,我们可以预处理出这个dp数组,在处理每一次询问的时候,直接调用这个数组的值就好了。最终复杂度O(n4),可以通过。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 105;
    
    int n, k, MOD;
    
    void sub(int& x, int y){
        x-=y;
        if(x<0)x+=MOD;
    }
    
    void add(int& x, int y){
        x+=y;
        if(x>MOD)x-=MOD;
    }
    
    int dp[N][N*N*N];
    
    void solve(){
        dp[0][0]=1;
        for(int i=1;i<=n;++i){
            int up=k*(i+1)*i/2;
            for(int j=0;j<=up;++j){
                dp[i][j]=dp[i-1][j];
                if(j>=i){
                    add(dp[i][j],dp[i][j-i]);
                }
            }
            for(int j=up;j>=(k+1)*i;--j){
                sub(dp[i][j],dp[i][j-(k+1)*i]);
            }
        }
    }
    
    void getAns(){
        for(int i=1;i<=n;++i){
            int ans=0;
            int l=i-1, r=n-i;
            int up=min(k*l*(l+1)/2,k*r*(r+1)/2);
            for(int j=0;j<=up;++j){
                add(ans,1ll*dp[l][j]*dp[r][j]%MOD);
            }
            ans=1ll*ans*(k+1)%MOD;
            add(ans,-1);
            cout<<ans<<endl;
        }
    }
    
    int main(){
        cin>>n>>k>>MOD;
    
        solve();
    
        getAns();
    
        return 0;
    }
    
    
  • 相关阅读:
    5大用例设计笔试大题,附详细解析!
    面试被问到:fiddler 在工作中有哪些应用?怎么破?
    Jmeter设置中文
    Git 操作
    测压数据处理脚本
    python通过126邮箱发送邮件
    Python读取Mysql数据并写入Excel
    Git基本操作命令
    python接口自动化框架探讨
    寒假每日一题(B
  • 原文地址:https://www.cnblogs.com/JohnRan/p/13773609.html
Copyright © 2020-2023  润新知