当前位置: 代码迷 >> 综合 >> 2021杭电7.1004 Link with Balls HDU - 7047 合并+组合数+插板法
  详细解决方案

2021杭电7.1004 Link with Balls HDU - 7047 合并+组合数+插板法

热度:25   发布时间:2023-11-28 03:29:01.0

题目链接

题目大意

给你两个数n m

一共有2*n个桶

其中奇数桶(2*i-1) 每个桶可以拿ki个 球

偶数桶(2*i)每个桶可以拿x<=i个球

问你有多少种方案让你拿的球=m

这题要理解好题意

首先对于每个奇数桶k是可以不同的

其次对于相同的桶如果拿的球数量不同也看作是不同的方案

题目思路

一开始想过合并但是 由于一开始理解错了题意

误认为所有的k都是一样的 遂放弃了奇偶合并 转而去考虑合并奇数项和合并偶数项 百思不得其解

最终在题解的帮助下才知道k是可以不同的

那么就转而去考虑每个i的奇偶合并的可能性

对于每一个奇数项 选择的数字是ki 他的前一项选择的数字是i-x

合并这两项得到的是(k+1)*i -x    (1<=x<=i-1 )

合并得到的新数字可以取任意的数 并且选择方案是唯一的

可能有人会问为什么要和前一项合并而不是和后一项

举个例子此时i=5 需要得到的值是10

假如和后一项合并  (k+1)*5-x    (1<=x<=5 )

那么k=1 x=0 符合题意 k=2 x=5也符合题意 这样的计算方案不唯一

就导致了最终结果 出现偏差

因此要与前一项合并

我们令最后剩下的第n个偶数桶选了x个球

则之前的n个任意项要选择 m-x个

用插板法相当于 将m-x球放在n个位置每个位置不是必须要放

转化为 将 n-1块隔板放在m-x+n-1个空隙里(每个空隙都至少要放一个)

C_{m-x+n-1}^{n-1}

ans=\sum_{x=0}^{n} C_{m-x+n-1}^{n-1}

由于C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m}

将上面消项化简为

ans = C_{m+n}^{n}-C_{m-1}^{n}

代码

#include <stdio.h>
#include <iostream>
#define MN 2000000
typedef long long ll;
using namespace std;
const int mod = 1000000007;
int n,m;
int fac[MN+5],inv[MN+5];ll qpow(ll bsc,ll y){ll ret = 1;while(y){if(y&1) ret = ret*bsc%mod;bsc = bsc*bsc%mod;y >>= 1; }return ret;
}void init(){fac[0] = 1;for(int i=1;i<=MN;i++)fac[i] = (ll)fac[i-1]*i%mod;inv[MN] = qpow(fac[MN],mod-2);for(int i=MN-1;i>=0;i--)inv[i] = (ll)inv[i+1]*(i+1)%mod;
}int C(int n,int m){if(m>n) return 0;return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{int t;init();cin>>t;while(t--){cin>>n>>m;int ans = C(m+n,n)-C(m-1,n);if(ans<0) ans += mod;printf("%d\n",ans);}return 0;
}

  相关解决方案