bzoj 4403 序列统计——转化成组合数的思路

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

先说说自己的想法吧。

设f[ i ][ j ]表示当前在倒数第 i 个位置,当前和后面的最高的列(最大的数)是 j 的方案数。

考虑当前填0,则用f[ i-1][ j ]转移;当前填1,相当于把后面的都消去最底下一行,用f[ i-1 ][ j-1 ]转移。

所以f[ i ][ j ]=∑(k:0~j)f[ i-1 ][ k ]。然后矩阵优化。

结果发现 j 的范围达到1e9,也就是要建1e9*1e9的矩阵。于是萎了。

看TJ:https://blog.csdn.net/Clove_unique/article/details/68491395

关键的思路可能在于发现随便选即可,之后排序。

没错,不用 +i 转换成升序也是可以这样转化的。很经典。

C( )里必须判断 if(n<m)return 0; !因为n%mod,m%mod时很容易传进n<m的参数!

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int mod=1e6+3;
int T,n,m,l,r,jc[mod+5],jcn[mod+5];
int pw(int x,int k)
{
  int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;
}
void init()
{
  jc[0]=1;
  for(int i=1;i<mod;i++)jc[i]=(ll)jc[i-1]*i%mod;
  jcn[mod-1]=pw(jc[mod-1],mod-2);
  for(int i=mod-2;i>=0;i--)jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
}
int C(int n,int m)
{
  if(n<m)return 0;//////
  return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;
}
int lucas(int n,int m)
{
  if(!m)return 1;if(n<mod&&m<mod)return C(n,m);
  return (ll)lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
int main()
{
  init();
  scanf("%d",&T);
  while(T--)
    {
      scanf("%d%d%d",&n,&l,&r);m=r-l+1;
      printf("%d
",(lucas(n+m,m)-1+mod)%mod);
    }
  return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9261729.html