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]Kj使

最终答案是,相同的值的方案数*(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;
}

posted @   John_Ran  阅读(308)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示