蒟蒻__stdcall终于更新博客辣~

一下午+一晚上=一道计数题QAQ

为什么计数题都这么玄学啊QAQ


Prelude

题目链接:这里是传送门= ̄ω ̄=

下面我将分几个步骤讲一下这个题的做法,大家不必一次看完,可以一点一点地推进思路,希望对锻炼大家的思维能力有帮助o( ̄▽ ̄)ブ。


Step 1

首先要看出来这是一个计数题对吧。。。

计数题有很多做法,对于这个题,我们考虑合理枚举,即不重复不遗漏地枚举所有情况,然后乘上一个组合数,并通过前缀和优化来降低复杂度。


Step 2

枚举什么东西呢?

我们考虑重新定义一下题目中的\(s\)和\(t\)。

我们定义\(t\)为,第一次取的蓝色球的位置,同时,为了构造出尽量多的方案,这个\(t\)要尽量地靠左。

举个栗子吧,比如我们想第一个取蓝色球,那么就有\(t = a + 1\),如果我们想等所有的红色球取完再取蓝色球,那么\(t = 1\)。

这里说的不太清楚。。。大家意会一下QAQ

于是我们首先枚举\(t\),即第一个取的蓝色球的位置,那么我们在取到这个球之前,首先需要从首部取\(a + 1 - t\)个红色球。

也就是说,我们得到的结果序列,是以\(a + 1 - t\)个红色球和一个蓝色球开始的,对于不同的\(t\),我们得到的序列肯定是不同的,不会重复。

同时,因为我们肯定要取蓝色球,所以也覆盖了所有情况而不会遗漏。


Step 3

确定了一个\(t\)之后,我们取走最前面的\(a + 1 - t\)个红色球和在\(t\)位置的一个蓝色球。剩余\(t - 1\)个红色球和\(b - 1\)个蓝色球。

接下来该枚举什么?

考虑现在一共有\(t + b - 2\)个球,我们取走\(b - 1\)个,使得剩下\(t - 1\)个球,然后\(t\)这个位置就没有用了,接下来就可以考虑确定\(s\)的位置。

于是我们枚举\(i\),即剩下的\(t - 1\)个球中,蓝色球的数量。

然后,确定了\(i\)之后,我们发现我们需要取走\(i\)个红色球和\(b - 1 - i\)个蓝色球。

容易发现,接下来准备取走的球,是不受位置限制的,颜色可以任意取,也就是说,这即将要取走的\(b - 1\)个球中,红色球和蓝色球可以排在任意位置。

于是,取走这\(b - 1\)个球的方案数就是\(C_{b-1}^{i}\)。

同样,当我们固定了\(t\)之后再枚举\(i\),也肯定是不重复不遗漏的,原因太显然了我就懒得讲了大家自己体会叭。。。


Step 4

现在我们剩了\(t - 1 - i\)个红色球和\(i\)个蓝色球。

现在\(t\)这个位置已经没法用了,我们还想要取蓝色球的话,需要新建一个位置\(s\),于是我们枚举\(s\)的位置。

注意,因为现在红色球只有\(t - 1 - i\)个,所以\(s\)最多枚举到\(t - i\)。

同理,确定了一个\(s\)之后,我们需要先取走\(t - i - s\)个红色球,然后再取走一个蓝色球,和上面的情况类似,这里也是不重复不遗漏的。


Step 5

现在我们只剩\(s - 1\)个红色球和\(i - 1\)个蓝色球了。

类似Step 3,我们考虑取走\(i - 1\)个球,剩余\(s - 1\)个球,枚举这剩余\(s - 1\)个球中,蓝色球的数量\(j\),那么我们要取走\(j\)个红色球和\(i - 1 - j\)个蓝色球。

同理,取这些球的时候是不受位置限制的,方案数是\(C_{i-1}^{j}\)。


Step 6

于是我们就只剩最后\(s - 1\)个球了,只能从首部一个一个取。


Step 7

我们枚举了\(t, i, s, j\)四个量,算法的时间复杂度为\(O(n^4)\)。

然后我们发现,枚举\(j\)并累加\(C_{i-1}^{j}\),实际上是杨辉三角第\(i-1\)行的一个前缀和,于是可以记\(sum[i][j]\)为杨辉三角第\(i\)行前\(j\)项的和,复杂度变为\(O(n^3)\)。

我们还能发现,枚举\(s\)并累加\(sum[i-1][min(s-1,i-1)]\),其实也是\(sum[i-1]\)的一个前缀和,于是记\(f[i][j]\)为\(sum[i]\)的前\(j\)项的和。

于是复杂度就变成了\(O(n^2)\)辣~

撒花花~★,°:.☆( ̄▽ ̄)/$:.°★

(我想了一整个下午加一整个晚上好叭QAQ)


Code

代码如下

#include <cstring>
#include <cstdio>
#include <algorithm> using namespace std;
typedef long long ll;
const int MAXN = 2010;
const int MOD = 1e9+7;
int _w; int C[MAXN][MAXN], sum[MAXN][MAXN], f[MAXN][MAXN];
void prelude() {
for( int i = 0; i < MAXN; ++i ) {
f[i][0] = sum[i][0] = C[i][0] = 1;
for( int j = 1; j <= i; ++j )
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD;
for( int j = 1; j < MAXN; ++j )
sum[i][j] = (sum[i][j-1] + C[i][j]) % MOD;
for( int j = 1; j < MAXN; ++j )
f[i][j] = (f[i][j-1] + sum[i][j]) % MOD;
}
} int solvet( int t, int b ) {
int ans = 1; // i == 0
for( int i = 1; i <= min(t-1, b); ++i )
ans = int((ans + (ll)f[i-1][t-i-1] * C[b][i]) % MOD);
return ans;
} int main() {
prelude();
int a, b;
_w = scanf( "%d%d", &a, &b );
if( !a || !b ) return puts("1"), 0;
int ans = 0;
for( int t = 1; t <= a+1; ++t )
ans = (ans + solvet(t, b-1)) % MOD;
printf( "%d\n", ans );
return 0;
}

【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数的更多相关文章

  1. Atcoder CODE FESTIVAL 2017 qual B E - Popping Balls 组合计数

    题目链接 题意 \(A+B\)个球排成一行,左边\(A\)个为红球,右边\(B\)个为蓝球. 最开始可以选择两个数\(s,t\),每次操作可以取左起第\(1\)或\(s\)或\(t\)个球.问有多少种 ...

  2. 题解【AtCoder - CODE FESTIVAL 2017 qual B - D - 101 to 010】

    题目:https://atcoder.jp/contests/code-festival-2017-qualb/tasks/code_festival_2017_qualb_d 题意:给一个 01 串 ...

  3. Atcoder Code Festival 2017 qual C 10.22 D题题解

    [题意概述] 给出一个只有小写字母的序列,问最少把序列分成几段可以满足每一段可以通过变换成为回文串.变换指的是交换子序列中的字母的位置. [题解] 我们把a~z分别设为2^0~2^25,每个子序列满足 ...

  4. Atcoder CODE FESTIVAL 2017 qual B D - 101 to 010 dp

    题目链接 题意 对于一个\(01\)串,如果其中存在子串\(101\),则可以将它变成\(010\). 问最多能进行多少次这样的操作. 思路 官方题解 转化 倒过来考虑. 考虑,最终得到的串中的\(' ...

  5. Atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning 回文串划分

    题目链接 题意 给定一个字符串(长度\(\leq 2e5\)),将其划分成尽量少的段,使得每段内重新排列后可以成为一个回文串. 题解 分析 每段内重新排列后是一个回文串\(\rightarrow\)该 ...

  6. Atcoder CODE FESTIVAL 2017 qual B C - 3 Steps 二分图

    题目链接 题意 给定一个无向图,\(n\)个点,\(m\)条边(\(n,m\leq 1e5\)). 重复如下操作: 选择相异的两点u,v满足从点u出发走三条边恰好能到达点v.在这样的u,v点对之间添一 ...

  7. atcoder/CODE FESTIVAL 2017 qual B/B(dfs染色判断是否为二分图)

    题目链接:http://code-festival-2017-qualb.contest.atcoder.jp/tasks/code_festival_2017_qualb_c 题意:给出一个含 n ...

  8. Atcoder CODE FESTIVAL 2017 qual C C - Inserting 'x' 回文串

    题目链接 题意 给定字符串\(s\),可以在其中任意位置插入字符\(x\). 问能否得到一个回文串,若能,需插入多少个\(x\). 思路 首先统计出现次数为奇数的字符\(cnt\). \(cnt\ge ...

  9. 101 to 010 Atcoder CODE FESTIVAL 2017 qual B D

    https://www.luogu.org/problemnew/show/AT3575 题解 根本不会.. 错误记录:缺少32行的转移.显然这个转移是必要的 #include<cstdio&g ...

随机推荐

  1. [CF1137]Museums Tour

    link \(\text{Description:}\) 一个国家有 \(n\) 个城市,\(m\) 条有向道路组成.在这个国家一个星期有 \(d\) 天,每个城市有一个博物馆. 有个旅行团在城市 \ ...

  2. 在Emacs 23里字体的调整(转自ChinaUnix.net)

    首先,在Emacs中,通过菜单Options --> Set Default Font,设置好你喜欢的字体. 然后,把光标放到你所在的字体上,用命令M-x describe-font来查看你当前 ...

  3. python format用法详解

    #常用方法:print('{0},{1}'.format('zhangk', 32)) print('{},{},{}'.format('zhangk','boy',32)) print('{name ...

  4. 数据库与数据仓库的比较Hbase——Hive

    数据仓库(Data Warehouse)是一个面向主题的(Subject Oriented).集成的(Integrate).相对稳定的(Non-Volatile).反映历史变化(Time Varian ...

  5. linux-ubuntu配置通过22端口远程连接

    当安装好ubuntu后获取到对应主机的ip地址,要想通过类似xshell这样的远程连接工具连接到ubuntu主机,需要在你刚刚安装好的ubuntu主机上安装openssh这个软件,才能通过远程来连接u ...

  6. java处理大文本2G以上

    面试中经常碰到类似问题,问题的关键我觉得是用设置一个缓冲区 还有一个思路 是通过Linux split 命令将文件直接切割成小文件,再进行处理再汇总. 或者jdk7提供的 forkjoin 框架,利用 ...

  7. python处理时间相关的方法(汇总)

    记录python处理时间的模块:time模块.datetime模块和calendar模块. python版本:2.7 在介绍模块之前,先说下以下几点: 1.时间通常有这几种表示方式: a.时间戳:通常 ...

  8. lintcode-248-统计比给定整数小的数的个数

    248-统计比给定整数小的数的个数 给定一个整数数组 (下标由 0 到 n-1,其中 n 表示数组的规模,数值范围由 0 到 10000),以及一个 查询列表.对于每一个查询,将会给你一个整数,请你返 ...

  9. 解决Ubuntu(Linux)平台下Sublime Text 3 安装中文输入支持库后 开启gnome-terminal报错的问题

    在Ubuntu下安装Sublim Text3后发现无法输入中文,按照此链接的方法解决后.然后用下列代码配置C++的编译系统: { "cmd":["g++",&q ...

  10. 关于window.open弹出窗口被阻止的问题

    原文:http://blog.csdn.net/fanfanjin/article/details/6858168 在web编程过程中,经常会遇到一些页面需要弹出窗口,但是在服务器端用window.o ...