Solution

相当于要你计算这样一个式子:

\[\sum_{x = 0}^m \left( \begin{array}{} m \\ x \end{array} \right) \left( \begin{array}{} k \\ n - m + 2x \end{array}{} \right)
\]

考虑到\(m\)非常大, 而\(k\)却比较小, 我们尝试将\(x\)的\(m\)相关转化为\(k\)相关. 我们用如下现实意义来考虑: 令\(N = n - m\), 则我们相当于有两堆球, 第一堆球以单个球为单位, 总共\(N\)个, 我们要在其中取出\(i\)个; 第二堆球以一对球连在一起为单位, 总共有\(m\)对, 我们要在其中取出任意多对球, 拆开放入第一堆中, 然后问你在第一堆中取\(k\)个球总共有多少种的方案.

这个问题仍然不好解决, 我们继续考虑: 我们假设这\(k\)个球中, 总共用了第二堆球中的\(j\)对. 也就是说, 这\(k\)个球中\(i\)个是在第一堆中取来的, 剩下\(k - i\)个用到了第二堆中的\(j\)对球, 其中每一对既有可能被用了一个, 也有可能用了两个. 考虑方案数: 在第一堆中取\(i\)个显然就是\(\left( \begin{array}{} N \\ i \end{array}{} \right)\); 我们用f[i][j]来表示在第2堆中用到\(i\)对, 并且总共取出\(j\)个球的方案数, 考虑\(f[i][j]\)的递归式:

\[f[i][j] = f[i - 1][j - 1] \times 2 + f[i - 1][j - 2]
\]

这样以来, 总共的方案数就是

\[\sum_i \sum_j \left( \begin{array}{} N \\ i \end{array}{} \right) f[i][N - k]
\]

考虑到询问有\(500\)组, 我们要作一些预处理, 记忆化某些信息.


#include <cstdio>
#include <cctype> namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1; char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int K = 300, MOD = (int)1e9 + 7;
int prod[K + 1], prodInv[K + 1], f[K + 1][K << 2], dwn[K + 1], _dwn[K + 1], pw[K + 1];
inline int power(int a, int x)
{
if(x < 0) return 0;
int res = 1;
for(; x; a = (long long)a * a % MOD, x >>= 1) if(x & 1) res = (long long)res * a % MOD;
return res;
}
inline int _C(int m)
{
if(m < 0) return 0;
return (long long)_dwn[m] * prodInv[m] % MOD;
}
inline int C(int m)
{
if(m < 0) return 0;
return (long long)dwn[m] * prodInv[m] % MOD;
}
inline void pretreat()
{
prod[0] = prodInv[0] = 1; for(int i = 1; i <= K; ++ i) prod[i] = (long long)prod[i - 1] * i % MOD, prodInv[i] = power(prod[i], MOD - 2);
f[0][0] = 1;
for(int i = 1; i <= K; ++ i) for(int j = 1; j <= i << 1; ++ j) f[i][j] = (f[i - 1][j - 1] * 2 % MOD + (j >= 2 ? f[i - 1][j - 2] : 0)) % MOD;
}
int main()
{ #ifndef ONLINE_JUDGE freopen("crash.in", "r", stdin);
freopen("crash.out", "w", stdout); #endif using namespace Zeonfai;
pretreat();
for(int T = getInt(); T --; )
{
int n = getInt(), m = getInt(), k = getInt(), ans = 0;
dwn[0] = 1; dwn[1] = m; for(int i = 2; i <= k; ++ i) dwn[i] = (long long)dwn[i - 1] * (m - i + 1) % MOD;
_dwn[0] = 1; _dwn[1] = n - m; for(int i = 2; i <= k; ++ i) _dwn[i] = (long long)_dwn[i - 1] * (n - m - i + 1) % MOD;
for(int i = 0; i <= k; ++ i) pw[i] = power(2, m - i);
for(int i = 0; i <= k; ++ i)
{
int cur = 0;
for(int j = (k - i + 1) / 2; j <= k - i; ++ j)
cur = (cur + (long long)C(j) % MOD * pw[j] % MOD * f[j][k - i] % MOD) % MOD;
ans = (ans + (long long)cur * _C(i) % MOD) % MOD;
}
printf("%d\n", ans);
}
}

2016北京集训测试赛(十七)Problem A: crash的游戏的更多相关文章

  1. 2016北京集训测试赛(十七)Problem C: 数组

    Solution 线段树好题. 我们考虑用last[i]表示\(i\)这个位置的颜色的上一个出现位置. 考虑以一个位置\(R\)为右端点的区间最远能向左延伸到什么位置: \(L = \max_{i \ ...

  2. 2016北京集训测试赛(十七)Problem B: 银河战舰

    Solution 好题, 又是长链剖分2333 考虑怎么统计答案, 我场上的思路是统计以一个点作为结尾的最长上升链, 但这显然是很难处理的. 正解的方法是统计以每个点作为折弯点的最长上升链. 具体的内 ...

  3. 2016北京集训测试赛(十六)Problem C: ball

    Solution 这是一道好题. 考虑球体的体积是怎么计算的: 我们令\(f_k(r)\)表示\(x\)维单位球的体积, 则 \[ f_k(1) = \int_{-1}^1 f_{k - 1}(\sq ...

  4. 2016北京集训测试赛(十六)Problem B: river

    Solution 这题实际上并不是构造题, 而是一道网络流. 我们考虑题目要求的一条路径应该是什么样子的: 它是一个环, 并且满足每个点有且仅有一条出边, 一条入边, 同时这两条边的权值还必须不一样. ...

  5. 2016北京集训测试赛(十六)Problem A: 任务安排

    Solution 这道题告诉我们, 不能看着数据范围来推测正解的时间复杂度. 事实证明, 只要常数足够小, \(5 \times 10^6\)也是可以跑\(O(n \log n)\)算法的!!! 这道 ...

  6. BZOJ 4543 2016北京集训测试赛(二)Problem B: thr 既 长链剖分学习笔记

    Solution 这题的解法很妙啊... 考虑这三个点可能的形态: 令它们的重心为距离到这三个点都相同的节点, 则其中两个点分别在重心的两棵子树中, 且到重心的距离相等; 第三个点可能在重心的一棵不同 ...

  7. 2016北京集训测试赛(十四)Problem B: 股神小D

    Solution 正解是一个\(\log\)的link-cut tree. 将一条边拆成两个事件, 按照事件排序, link-cut tree维护联通块大小即可. link-cut tree维护子树大 ...

  8. 2016北京集训测试赛(十四)Problem A: 股神小L

    Solution 考虑怎么卖最赚钱: 肯定是只卖不买啊(笑) 虽然说上面的想法很扯淡, 但它确实能给我们提供一种思路, 我们能不买就不买; 要买的时候就买最便宜的. 我们用一个优先队列来维护股票的价格 ...

  9. 2016北京集训测试赛(十三) Problem B: 网络战争

    Solution KD tree + 最小割树

随机推荐

  1. 关于spark入门报错 java.io.FileNotFoundException: File file:/home/dummy/spark_log/file1.txt does not exist

    不想看废话的可以直接拉到最底看总结 废话开始: master: master主机存在文件,却报 执行spark-shell语句:  ./spark-shell  --master spark://ma ...

  2. SSRS 报表管理器 http://localhost/Reports HTTP500 内部错误处理过程

    原文地址:http://www.cnblogs.com/zzry/p/5716056.html 安装了很多机器的sqlserverBI 组件 初始安装配置下 浏览报表管理器 http://localh ...

  3. 15、响应式布局和BootStrap 全局CSS样式知识点总结-part2

    1.表格 <div class="container"> <table class="table "> <thead> &l ...

  4. 【Two Sum】cpp

    题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...

  5. Oracle 学习笔记(Windows 环境下安装 + PL/SQL)

    Oracle 安装.PL/SQL 配置使用  前言:因更换机械硬盘为 SSD 固态硬盘装了新 Windows 7 系统,需要重新搭建开发环境,把 Oracle 安装过程和 PL/SQL 配置使用做下笔 ...

  6. Android view相关与自定义View

    一.关于view的机制的问答 1.gesturedetector和ontouchevent的区别 gesturedetector指的是手势检测器,根据动态手势的运动特性,提出了速率边沿检测算法来分割手 ...

  7. quagga源码学习--BGP协议对等体连接建立的状态机

    创建完bgp peer之后,就要bgp start了,不然费那么大劲创建出来不做事情就销毁了,就很尴尬了. 那么对等体一旦start起来,就会进入各自的状态,在不同的状态下处理各自的事件消息. 下面列 ...

  8. CDOJ 1256 二维前缀和处理

    昊昊喜欢运动 他NN 天内会参加MM 种运动(每种运动用一个[1,m][1,m] 的整数表示) 舍友有QQ 个问题 问昊昊第ll 天到第rr 天参加了多少种不同的运动 Input 输入两个数NN , ...

  9. Python之时间:time模块

    import time   对于时间,使用最频繁的模块 1.获取当前时间 (1)时间戳 time.time() 时间戳:从1970年1月1日0点开始到现在按秒计算的偏移量 (2)时间元组 time.l ...

  10. iOS多线程:『GCD』详尽总结 ---(转)

    文章:https://bujige.net/blog/iOS-Complete-learning-GCD.html 文中 Demo 我已放在了 Github 上,Demo 链接:https://git ...