zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    excel打印预览后整个表格中按页显示虚线,打印时就会打印很多页
    4.8 自定义下拉菜单模式Spinner与setDropDownViewResource
    1.2Matlab基本语法和基本操作.
    CTime类的一个BUG
    【转载】PE_Info 之DIY
    ubuntu使用记录
    反VM测试成功
    获取MAC地址
    【转载】秒到oep,支持所有壳,包括vmp
    【转载】Make your owner PE Protector
  • 原文地址:https://www.cnblogs.com/wmrv587/p/8638408.html
Copyright © 2011-2022 走看看