牡牛和牝牛

牡牛和牝牛

有n个0或者1,进行全排列,要求任意两个0间至少有k个1,询问其方案数%5000011。
对于全部数据,对于全部数据,\(1≤N≤10^5,0≤K<N\)。

解:

显然为排列组合问题,考虑方向自然为通项与递推方程。

法一(通项公式):

首先0决定了1的摆放,其次数据范围支持对0的枚举,于是枚举0的个数,设其x,于是每个间隔至少要有k个1,不妨先构造让其满足条件,需要(x-1)k个1,显然有\((x-1)k+x\leq n\Rightarrow [\frac{n+k}{k+1}]\),于是问题即变成对于剩下的1的插入0之间的间隔,
共有x+1个间隔,剩下的1的个数为\(n-(x-1)k-x\)。

思路一:


间隔是有序的,而1是无序的,不好解决无序的元素放入有序的盒子的方案数的问题,反过来看则是有序的间隔放入无序的1,而间隔可以多次放入同一个1,即可重组合,于是方案数不难得知为\(C_{n-(x-1)k}^{x}\)。


思路二:


插入组合问题很困难,于是考虑组合转排列,转换模型,即等价于\(n-(x-1)k-x\)个1与\(x\)个0进行全排列,根据可重排列公式有:
\[\frac{(n-(x-1)k-x+x)!}{x!(n-(x-1)k-x)!}=\frac{(n-(x-1)k)!}{x!(n-(x-1)k-x)!}\]
\[=C_{n-(x-1)k}^{x}\]



所以只要枚举0的个数,代入公式累加即可。

参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define ll long long
#define yyb 5000011
using namespace std;
ll jc[100001],jv[100001],lsy(1);
il ll pow(ll,ll),c(int,int);
int main(){
    int n,i,j,k,li;scanf("%d%d",&n,&k);
    for(i=jc[0]=1;i<=n;++i)jc[i]=jc[i-1]*i%yyb;
    jv[n]=pow(jc[n],yyb-2),li=(n+k)/(k+1);
    for(i=n,jv[0]=1;i>1;--i)jv[i-1]=jv[i]*i%yyb;
    for(i=1;i<=li;++i)(lsy+=c(n-(i-1)*k,i))%=yyb;
    printf("%lld",lsy);
    return 0;
}
il ll c(int n,int r){
    if(n<r)return 0;
    return jc[n]*jv[r]%yyb*jv[n-r]%yyb;
}
il ll pow(ll x,ll y){
    ll ans(1);
    while(y){
        if(y&1)ans=ans*x%yyb;
        x=x*x%yyb,y>>=1;
    }return ans;
}

法二(递推方程)

经验告诉我们以序列长度为状态,于是设\(f[i]\)表示填到第i个位置的方案数,显然策略为填0或者1,填1恒满足累加\(f[i-1]\),填0导致前k个都不能填0,故累加\(f[i-k-1]\),于是有:
\[f[i]=f[i-1]+f[i-k-1]\]

参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define yyb 5000011
using namespace std;
int dp[100001];
int main(){
    int n,k,i;
    scanf("%d%d",&n,&k);
    for(i=1;i<=k+1;++i)dp[i]=i+1;
    for(i=k+2;i<=n;++i)
        dp[i]=(dp[i-k-1]+dp[i-1])%yyb;
    printf("%d",dp[n]);
    return 0;
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10780306.html

时间: 2024-11-10 10:26:54

牡牛和牝牛的相关文章

BZOJ 3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛( dp )

水题...忘了取模就没1A了.... --------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; const int MOD = 5000011; const int maxn = 100009; int dp[maxn], n, k; int main() { cin >> n >> k;

bzoj3398[Usaco2009 Feb]Bullcow 牡牛和牝牛*

bzoj3398[Usaco2009 Feb]Bullcow 牡牛和牝牛 题意: n头牛,其中有牡牛和牝牛两种,要求任意两只牡牛中要有k只牝牛,问几种方案.n≤100000 题解: dp.f[i]表示第i头牛为牡牛的方案数,f[i]=sigma(j,1,i-k-1)f[j],这个可以用前缀和维护,最后答案为sigma(i,1,n)f[i]. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

[BZOJ3398] [Usaco2009 Feb]Bullcow 牡牛和牝牛(动态规划)

3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 235  Solved: 159[Submit][Status][Discuss] Description 约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛. 请计算一共有多少种排

Bullcow 牡牛和牝牛(bzoj 3398)

Description 约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛. 请计算一共有多少种排队的方法.所有牡牛可以看成是相同的,所有牝牛也一样.答案对5000011取模 Input 一行,输入两个整数N和K. Output 一个整数,表示排队的方法数. Sample Input 4 2 Sample Output 6 样例说明 6种方法分

bzoj:3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛

Description 约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛. 请计算一共有多少种排队的方法.所有牡牛可以看成是相同的,所有牝牛也一样.答案对5000011取模 Input 一行,输入两个整数N和K. Output 一个整数,表示排队的方法数. Sample Input 4 2 Sample Output 6 初二在纪中集训的时候

【BZOJ】【3398】【USACO 2009 Feb】Bullcow 牡牛和牝牛

组合计数 排列组合求总方案数 这个可以用一个一维的动态规划解决: f[i][0]表示第i头牛是牝牛的方案数 f[i][1]表示第i头牛是牡牛的方案数 则转移为:f[i][0]=f[i-1][0]+f[i-1][1]; f[i][1]=f[i-K-1][0]+f[i-K-1][1]; 常数优化:将取模运算改为if判断语句……可从20ms降为16ms 1 /************************************************************** 2 Problem

bzoj3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛(排列组合)

原题链接 题目描述:约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛.请计算一共有多少种排队的方法.所有牡牛可以看成是相同的,所有牝牛也一样.答案对5000011取模. 输入格式:一行,输入两个整数N和K. 输出格式:一个整数,表示排队的方法数. 输入样例: 4 2 输出样例: 6 解析:一道比较简单的题,直接组合数算一下即可. 代码如下:

1652:牡牛和牝牛

[题目描述] 原题来自:USACO 2009 Feb. Silver 牡 mǔ,畜父也.牝 pìn,畜母也. --<说文解字> 约翰要带 N 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 K 只牝牛. 请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 5000011 取模. [输入] 一行,输入两个整数 N 和 K . [输出] 一个整数,表示排队的方法数. [

BZOJ 3398 牡牛和牝牛

dp. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define mod 5000011 using namespace std; int n,k,dp[maxn][3],sum[maxn]; int main() { scanf("%d%d",&n,&k); dp[1][1]=