zoukankan      html  css  js  c++  java
  • 19_07_09校内训练[分组]

    题意

    将n个数分为若干组,每组中最小的数不能比该组的元素总数多,求方案数。n<=2000。


    思考

    若得到n个数的一种大小的划分,则可以简单地求出其方案数。将其从大到小排序后,令largeri为大于等于i的数字的个数,b[i]为第i个组的大小,sum为b的前缀和,则对于第i个组,其贡献为C(larger[b[i]]-sum[i-1],b[i])。同时若有c个bi,则还要除以c!。

    由于只和最小的数,最小的数的个数有关,令f[i][j][k]为选中了前i个数,当前最小的bi为j,bi有k个。只有k为1时,可以用前缀和优化。当k不为1时,从k-1转移过来,并且除以k。复杂度O(n^3)。

    注意到j*k<=i,有用的状态只有n^2logn个,直接动态开数组即可。


    代码

      1 #include<bits/stdc++.h>
      2 #define mod 998244353
      3 using namespace std;
      4 typedef long long int ll;
      5 const int maxn=2E3+5;
      6 int n,a[maxn],larger[maxn],b[maxn],top;
      7 int ans,fac[maxn],invC[maxn],sum[maxn][maxn],inv[maxn];
      8 int*f[maxn][maxn];
      9 int C[maxn][maxn];
     10 ll qpow(ll x,ll y)
     11 {
     12     ll base=x,ans=1;
     13     while(y)
     14     {
     15         if(y&1)
     16             ans=ans*base%mod;
     17         base=base*base%mod;
     18         y>>=1;
     19     }
     20     return ans;
     21 }
     22 inline void add(int&x,int y)
     23 {
     24     ll g=(ll)x+(ll)y;
     25     if(g>=mod)
     26         g-=mod;
     27     x=g;
     28 }
     29 void init()
     30 {
     31     fac[0]=1;
     32     for(int i=1;i<=n;++i)
     33         fac[i]=(ll)fac[i-1]*(ll)i%mod;
     34     invC[n]=qpow(fac[n],mod-2);
     35     for(int i=n-1;i>=0;--i)
     36         invC[i]=(ll)invC[i+1]*(ll)(i+1)%mod;
     37     for(int i=1;i<=n;++i)
     38         inv[i]=qpow(i,mod-2);
     39     C[0][0]=1;
     40     for(int i=1;i<=n;++i)
     41     {
     42         C[i][0]=1;
     43         for(int j=1;j<=i;++j)
     44         {
     45             C[i][j]=C[i-1][j];
     46             add(C[i][j],C[i-1][j-1]);
     47         }
     48     }
     49 }
     50 inline int read()
     51 {
     52     char ch=getchar();
     53     while(ch<'0'||'9'<ch)
     54         ch=getchar();
     55     int sum=ch-'0';
     56     ch=getchar();
     57     while('0'<=ch&&ch<='9')
     58     {
     59         sum=sum*10+ch-'0';
     60         ch=getchar();
     61     }
     62     return sum;
     63 }
     64 int main()
     65 {
     66     freopen("game.in","r",stdin);
     67     freopen("game.out","w",stdout);
     68     ios::sync_with_stdio(false);
     69     n=read();
     70     init();
     71     for(int i=1;i<=n;++i)
     72     {
     73         a[i]=read();
     74         if(a[i]==0)
     75         {
     76             cout<<0<<endl;
     77             return 0;
     78         }
     79         ++larger[a[i]];
     80     }
     81     for(int i=n-1;i>=1;--i)
     82         larger[i]+=larger[i+1];
     83     for(int i=1;i<=n;++i)
     84         for(int j=1;j<=i+1;++j)
     85         {
     86             f[i][j]=new int[i/j+4];
     87             for(int k=0;k<=i/j+3;++k)
     88                 f[i][j][k]=0;
     89         }
     90     for(int j=1;j<=n+1;++j)
     91     {
     92         f[0][j]=new int[3];
     93         for(int k=0;k<=2;++k)
     94             f[0][j][k]=0;
     95     }
     96     f[0][n+1][0]=1;
     97     for(int i=1;i<=n+1;++i)
     98         sum[0][i]=1;
     99     for(int i=1;i<=n;++i)
    100     {
    101         for(int j=1;j<=i;++j)
    102         {
    103             if(sum[i-j][j+1])
    104                 f[i][j][1]=(ll)sum[i-j][j+1]*(ll)C[larger[j]-i+j][j]%mod;
    105             for(int k=2;i-j*k>=0;++k)
    106             {
    107                 if(f[i-j][j][k-1])
    108                     f[i][j][k]=(ll)f[i-j][j][k-1]*(ll)inv[k]%mod*(ll)C[larger[j]-i+j][j]%mod;
    109             }
    110         }
    111         for(int j=i+1;j>=1;--j)
    112         {
    113             sum[i][j]=sum[i][j+1];
    114             for(int k=1;i-j*k>=0;++k)
    115                 add(sum[i][j],f[i][j][k]);
    116         }
    117     }
    118     ans=0;
    119     for(int i=1;i<=n;++i)
    120         for(int j=1;n-i*j>=0;++j)
    121             add(ans,f[n][i][j]);
    122     cout<<ans<<endl;
    123     return 0;
    124 }
    View Code
  • 相关阅读:
    equa与==的区别
    使用Log4j进行日志操作
    动态代理的步骤
    批量插入使用SqlBulkCopy
    SQL之开窗函数二——在复杂场景中的实际运用
    SQL Server数据类型详解
    SQL Server遍历表的几种方法
    SQL Server之表变量
    SQL Server之字符串处理函数
    SQL Server之String_Split函数(SQL Server2016版本以上使用)
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/11157122.html
Copyright © 2011-2022 走看看