bzoj 3398 [Usaco2009 Feb]Bullcow 牡牛和牝牛——前缀和优化dp / 排列组合

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3398

好简单呀。而且是自己想出来的。

dp[ i ]表示最后一个牡牛在 i 的方案数。

当前位置放牝牛,之前的dp[ k ]不变;当前位置放牡牛,出现了dp[ i ],值是距离大于k的dp[ j ]的和,所以可以前缀和优化。

当然有dp[0]啦。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+5,mod=5000011;
int dp[N],c[N],n,k;
int main()
{
  scanf("%d%d",&n,&k);
  dp[0]=1;c[0]=1;
  for(int i=1;i<=n;i++)dp[i]=c[max(0,i-k-1)],c[i]=(c[i-1]+dp[i])%mod;
  printf("%d\n",c[n]);
  return 0;
}
View Code

但是这其实是排列组合的题目。https://www.cnblogs.com/harden/p/6286182.html

逆元不预处理而是现弄其实也挺方便的。“古代猪文”那道题预处理阶乘逆元似乎爆了什么。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+5,mod=5000011;
int n,k,jc[N],ans;
void init()
{
  jc[0]=1;
  for(int i=1;i<=n;i++)jc[i]=(long long)jc[i-1]*i%mod;
}
int pw(int x,int k)
{
  int ret=1;while(k){if(k&1)ret=(long long)ret*x%mod;x=(long long)x*x%mod;k>>=1;}return ret;
}
int C(int i,int j)
{
  return (long long)jc[i]*pw(jc[j],mod-2)%mod*pw(jc[i-j],mod-2)%mod;
}
int main()
{
  scanf("%d%d",&n,&k);
  init();
  int lm=n/(k+1)+1-(n%(k+1)==0);
  for(int i=1;i<=lm;i++)(ans+=C(n-k*(i-1),i))%=mod;// no i=0
  printf("%d",(ans+1)%mod);
  return 0;
}

 

posted on 2018-07-03 19:41  Narh  阅读(205)  评论(0编辑  收藏  举报

导航