题意

将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

转载于:https://www.cnblogs.com/GreenDuck/p/11157122.html

19_07_09校内训练[分组]相关推荐

  1. 校内训练赛题解第三篇

    校内训练赛题解 人气估值 解题思路 脑力训练计划 (模拟 + 字符串) 解题思路 大暑赛期(贪心 + 思维) 人气估值 题目描述 你是某动画制作公司的企划部长.如今动画制作公司制作的东西,已经不仅仅局 ...

  2. 19_05_01校内训练[划分]

    题意 给出长度为n的序列,只有1,0,-1.要求将其划分为若干长度在[L,R]之间的连续序列,一个序列若和大于0,造成1的贡献:若小于0,造成-1的贡献:否则没有贡献.求最大的贡献. 时间复杂度要求n ...

  3. fzyzojP3372 -- [校内训练20171124]博弈问题

    对于每个点都要答案 还是异或 trie树合并石锤了 朴素枚举是O(n^2*17)的 怎么办呢? 我们发现合并的时候,一些部分的trie的子树还是不变的 改变的部分也就是合并的复杂度可以接受 鉴于大部分 ...

  4. 20170910校内训练

    CCT 最近学校又发了n本五三题霸,BBS看到后十分高兴.但是,当他把五三拿到手后才发现,他已经刷过这些书了!他又认真地看了一会儿,发现新发的这些五三是2017版的,而他刷的是2016版的.现在他想找 ...

  5. 20170908校内训练

    题意: 学过博弈论的同学都知道Nim游戏后手必胜的条件是异或和为0 给定一棵树 ,支持修改单点点权,询问链上异或和 预处理每个点到根的路径的异或和 由于异或的特殊性质,在求链x->y的异或和的时 ...

  6. 19_03_26校内训练[魔法卡片]

    题意 有n张有序的卡片,每张卡片上恰有[1,m]中的每一个数,数字写在正面或反面.每次询问区间[l,r],你可以将卡片上下颠倒,问区间中数字在卡片上方的并的平方和最大是多少.q,n*m≤1,000,0 ...

  7. 平面图转对偶图19_03_21校内训练 [Everfeel]

    对于每个平面图,都有唯一一个对偶图与之对应.若G'是平面图G的对偶图,则满足: G'中每一条边的两个节点对应着G中有公共边的面,包括最外部无限大的面. 直观地讲,红色标出来的图就是蓝色标出的图的对偶图 ...

  8. 19_05_01校内训练[polygon]

    题意 把一个边长为1的正n边形放到一个正m边形中,要求m边形完全覆盖n边形,可以有交点,并且中心重合.求正m边形的最小边长,至少精确到6位.要求logn计算. 思考 先考虑m|n的情况. 我们知道,正 ...

  9. [3.30校内训练赛]

    来自FallDream的博客,未经允许,请勿转载,谢谢. --------------------------------------------------- ditoly这次打好了虐爆我们的主意, ...

最新文章

  1. 缓存雪崩缓存击穿缓存穿透的本质
  2. 分割BiSeNet笔记
  3. Cissp-【第1章 安全和风险管理】-2020-12-03(1页-32页)
  4. linux sort -w32,WIN32汇编: 31.列表视图控件
  5. sqoop 1.4.4-cdh5.1.2快速入门
  6. Mybatis开发CRUD
  7. Failed:(13: Permission denied)导致访问浏览器出现Nginx 500 Internal Server Error
  8. 前端学习(2245)vue值造轮子之需求设计
  9. 哪个Linux发行版运行kvm,如何在Linux发行版上安装和配置KVM和Open vSwitch
  10. 转: SQL Server Analysis Service中Cube的结构
  11. 遍历点击事件(屏蔽同类名的其它点击事件,防止多次请求)
  12. 失态的三星正在把华为手机送上全球第一宝座
  13. 机器视觉(9)搞懂机器视觉基本内容,这份PPT就够了!
  14. python_opencv 黑白图片之白色部分单独分离
  15. 前端低代码工具amis使用文档
  16. 手把手教你做树莓派魔镜-MagicMirror(一)-准备工作
  17. Yocto系列讲解[实战篇]44 - bb文件中函数实操演示(2)
  18. python的 networkx画网络结构图,节点大小能够随权重变化
  19. 记录一次Visual Studio运行webservice调用中控打卡机出现的问题
  20. Windows:直接使用命令运行一个程序

热门文章

  1. vue element序号翻页连续排序
  2. 【设计模式笔记】代理模式
  3. 28和lba48命令格式区别_常用命令使用
  4. mysql技术任务_MySQL基础教程(13)MySQL计划任务
  5. php mysql 任务队列_PHP+MySQL实现消息队列步骤详解
  6. linux内存映射起始地址,内存初始化代码分析(三):创建系统内存地址映射
  7. sublime text3 快速生成方法注释
  8. vue使用iframe 子页面调用父页面的方法
  9. 《深入理解计算机系统》 CSAPP 入坑推荐
  10. 【AcWing】103. 电影(离散化)