025 Roaming (Atcoder 5312)

2 篇文章 0 订阅
2 篇文章 0 订阅
  • 题目链接 Atcoder 5312
  • 题意:
    数组a[n],起初每个位置都为1,可以进行k次操作,把某个位置的1移到另一个位置,k次操作后得到一个最终数组,求最终数组的可能情况数。(可以与原数组重复)对1e9+7取模。
    3 ≤ n ≤ 2 e 5 3 \leq n \leq 2e5 3n2e5
    2 ≤ k ≤ 1 e 9 2\leq k\leq 1e9 2k1e9
  • 分析:
    原问题等价于n个球装进n个不同的箱子里,至多有k个箱子为空,问方案数。
    下面给出简单的证明:
    对于任意的 2 ≤ k 2 \leq k 2k,均能移动某个数字两次达成k-1个数为0,互换两个数的位置达成k-2个数为0,因此对于小于k的任何个数为0都有可能。与投球问题等价。
    新问题中,若 n < k n<k n<k所有方案数都能取到,反之则要减去 k + 1 → n − 1 k+1 \rightarrow n-1 k+1n1个空箱对应的方案数。
    总方案数为 ( n n + n − 1 ) { n\choose n+n-1} (n+n1n) n − i n-i ni个空箱对应的方案数 ( i n ) × ( n − i − 1 n − 1 ) {i\choose n} \times {n-i-1\choose n-1} (ni)×(n1ni1),也等于 i i i个空箱对应的方案数。(从n个箱子中选 i i i个不作为空箱,n个球装进n-i个箱子里,整理一下也可以写成这样 ( i n ) × ( i − 1 n − 1 ) {i\choose n} \times {i-1\choose n-1} (ni)×(n1i1)
  • 代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=4e5+10;//要求2*n的组合数注意开两倍
const int mod=1e9+7;
ll fac[maxn],inv[maxn];
void gcd(ll a,ll b,ll &d,ll &x, ll &y){
	if(b){
		gcd(b,a%b,d,y,x); y-=x*(a/b);
	}
	else {
		d=a,x=1,y=0;
	}
}
void init(){
	fac[0]=fac[1]=1;
	for(int i=2;i<maxn;i++)
		fac[i]=fac[i-1]*i%mod;
}
ll c(ll n,ll k){
	ll x,y,d;
	ll tmp=(fac[k]*fac[n-k])%mod;
	gcd(tmp,mod,d,x,y);
	y=fac[n]*(x%mod)%mod;
	if(y<0) y+=mod;
	return y;
}
int main(){
	ll n,k;
	init();
	cin>>n>>k;
	ll ans=c(2*n-1,n);
	if(k>=n-1){
		//cout<<0;
		cout<<ans; return 0; 
	}
	else {
		for(int i=1;i<n-k;i++){
			ans-=c(n,i)*c(n-1,i-1)%mod;
			ans+=mod;
			ans%=mod;
		}
		cout<<ans;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值