BZOJ3612 [Heoi2014]平衡 整数划分
2024-10-20 00:44:00
[Heoi2014]平衡
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 348 Solved: 273
[Submit][Status][Discuss]
Description
下课了,露露、花花和萱萱在课桌上用正三棱柱教具和尺子摆起了一个“跷跷板”。
这个“跷跷板”的结构是这样的:底部是一个侧面平行于地平面的正三棱柱教具,
上面 摆着一个尺子,尺子上摆着若干个相同的橡皮。尺子有 2n + 1 条等距的刻度线,
第 n + 1 条 刻度线恰好在尺子的中心,且与正三棱柱的不在课桌上的棱完全重合。
露露发现这个“跷跷板”是不平衡的(尺子不平行于地平面)。于是,她又在尺
子上放 了几个橡皮,并移动了一些橡皮的位置,使得尺子的 2n + 1 条刻度线上都恰
有一块相同质 量的橡皮。“跷跷板”平衡了,露露感到很高兴。
花花觉得这样太没有意思,于是从尺子上随意拿走了 k 个橡皮。令她惊讶的事
情发生了: 尺子依然保持着平衡!
萱萱是一个善于思考的孩子,她当然不对尺子依然保持平衡感到吃惊,因为这
只是一个 偶然的事件罢了。令她感兴趣的是,花花有多少种拿走 k 个橡皮的方法
,使得尺子依然保 持平衡?
当然,为了简化问题,她不得不做一些牺牲——假设所有橡皮都是拥有相同质量的
质点。但即使是这样,她也没能计算出这个数目。放学后,她把这个问题交给了她
的哥哥/ 姐姐——Hibarigasaki 学园学生会会长,也就是你。当然,由于这个问题
的答案也许会过于 庞大,你只需要告诉她答案 mod p 的值。
Input
第一行,一个正整数,表示数据组数 T(萱萱向你询问的次数)。
接下来 T 行,每行 3 个正整数 n, k, p。
Output
共 T 行,每行一个正整数,代表你得出的对应问题的答案。
Sample Input
10
6 5 10000
4 1 10000
9 6 10000
4 6 10000
5 1 10000
8318 10 9973
9862 9 9973
8234 9 9973
9424 9 9973
9324 9 9973
6 5 10000
4 1 10000
9 6 10000
4 6 10000
5 1 10000
8318 10 9973
9862 9 9973
8234 9 9973
9424 9 9973
9324 9 9973
Sample Output
73
1
920
8
1
4421
2565
0
446
2549
1
920
8
1
4421
2565
0
446
2549
HINT
T <= 20,1 <= n <= 10000,1 <= k <= 10,2 <= p <= 10000,且 k <= 2n+1。
设f(i, j)表示把i分成j个不同的且<= n的整数的方案数。
考虑一般的整数划分数问题,f(i, j) = f(i-1, j-1) + f(i-j, j),其中第一项表示新填一个1,第二项表示把所有数都加1。
顺着这个思路,我们先考虑“不同”这个限制。
显然我们不能直接新填一个1,所以我们考虑把所有数加1,搞出来一个1,第一项得出为f(i-j, j-1)
第二项同样为f(i-j, j).
所以状态转移方程为f(i, j) = f(i-j, j) + f(i-j, j-1).
再考虑不能超过n这个限制,如果有超过n的数,显然它只有一个,而且是n+1,所以我们把这些情况减掉,即f(i-n-1, j-1).
统计答案时,考虑选了0和不选0,两种情况,并特判k=1.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101001
#define M 15
using namespace std;
int n,m,p,w;
int f[N][M]; // f[i][j] 表示
//将i划分成j个互不相同的正整数,
// 且最大不超过n 的划分方案数
int main()
{
int i,j,k,g;
f[][]=;
for(scanf("%d",&g);g--;)
{
scanf("%d%d%d",&n,&m,&p);
if(m==)
{
puts("");
continue;
}
w=n*(m-);
for(i=;i<=w;i++)
for(j=;j<m;j++)
{
f[i][j]=(i>=j?(f[i-j][j]+f[i-j][j-]):);
f[i][j]=(i>=n+)?(f[i][j]-f[i-n-][j-]):f[i][j];
f[i][j]=(f[i][j]%p+p)%p;
}
long long ans=;
for(i=;i<=w;i++)
for(j=;j<m;j++)
ans+=f[i][j]*f[i][m-j],ans%=p;
for(i=;i<=w;i++)
for(j=;j<m-;j++)
ans+=f[i][j]*f[i][m--j],ans%=p;
printf("%lld\n",ans);
}
}
最新文章
- JavaScriptSerializer序列化时间处理
- Linux下实现获取远程机器文件
- gcc编译器基本命令和vi编辑器2
- 基于FPGA的信号消抖
- 重操JS旧业第一弹:Script与JS加载
- 学习java 的经验
- 初学安卓开发随笔之 Menu、toast 用法、活动的四种启动模式 以及 一个方便的Base活动类使用方法
- 函数声明 和 var声明的优先级
- [C++ Primer Plus] 第8章、函数探幽(二)课后习题
- 《xxx系统》质量属性战术
- locate中使用variant
- php之函数
- bootstrap css布局
- 2-7 hash
- [Openwrt扩展中篇]添加Aria2和webui
- Elasticsearch零停机时间更新索引配置或迁移索引
- TMDXEVM6678L EVM开发板初使用(1)
- Error: Chromium revision is not downloaded. Failed to download Chromium
- 通过脚本同时运行几个spider
- JavaSE---Collections