• CS Academy #32 G


    题意:

      

    分析:

      考虑如何求方案数

      dp[i][j]表示i个数字的和为j的方案数,这是个经典问题,转移有两种,一个是填一个数字1,一个是整体加1

      然后这个问题并不是求方案数,而是求对应的权值和

      我们很容易想到dp[i][j]维护对应的m个下降幂Σx^i,最后再用斯特林数还原成m次幂

      但这样时间复杂度是O(nmk)的,无法接受

      题解给出了一个很妙的想法,我们去计算每个数字对答案的贡献,我们只关心这个数字出现的次数,不妨设我们现在考虑数字x

      x出现总次数={x恰好出现一次的方案数}*1+{x恰好出现两次的方案数}*2+......

      这样无法求解

      但可以转换成这样:

      x出现总次数={x至少出现一次的方案数}+{x至少出现两次的方案数}+.......

            =dp[k-1][n-x]+dp[k-2][n-2x]+dp[k-3][n-3x]+.......

      这样就可以O(nk)解决了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=4096,mod=1e9+7;
     4 int dp[maxn+5][maxn+5];
     5 int n,k,m;
     6 int ans=0;
     7 void inc(int &a,int b)
     8 {
     9     a=(a+b)%mod;
    10 }
    11 int Pow(long long a,int b)
    12 {
    13     long long ans=1;
    14     while(b)
    15     {
    16         if(b&1) ans=ans*a%mod;
    17         a=a*a%mod;
    18         b>>=1;
    19     }
    20     return ans;
    21 }
    22 int main()
    23 {    scanf("%d%d%d",&n,&k,&m);
    24     dp[0][0]=1;
    25     for(int i=1;i<=k;++i)
    26         for(int j=1;j<=n;++j)
    27         {
    28             if(j>=1)
    29             inc(dp[i][j],dp[i-1][j-1]);
    30             if(j>=i-1)
    31             inc(dp[i][j],dp[i][j-i]);
    32         }
    33     for(int i=1;i<=n;++i)
    34     {
    35         int s=0;
    36         for(int j=1;j<=k&&i*j<=n;++j)
    37             inc(s,dp[k-j][n-i*j]);
    38         inc(ans,1LL*s*Pow(1LL*i,m)%mod);
    39     }
    40     printf("%d
    ",ans);
    41     return 0;
    42 }
    View Code
  • 相关阅读:
    CSP-S2019 退役记
    近期考试反思
    有关近期情况的总结与反思
    我好难啊
    AFO
    智障错误集锦
    关于博客密码【asd
    关于csp-s的各种问题整理
    CSP-S 临别赠言( 二 )
    分层图最短路 乱搞分享
  • 原文地址:https://www.cnblogs.com/wmrv587/p/8638408.html
Copyright © 2020-2023  润新知