• bzoj 4403: 序列统计【lucas+组合数学】


    首先,给一个单调不降序列的第i位+i,这样就变成了单调上升序列,设原来数据范围是(l,r),改过之后变成了(l+1,r+n)
    在m个数里选长为n的一个单调上升序列的方案数为( C_m^n ),也就是随便选n个数只能组成惟一的单调上升序列,所以要求的式子就变成了

    [sum_{i=1}^{n}C_{r-l+i}^{i} ]

    这样看着比较难受,我们把它改成

    [sum_{i=1}^{n}C_{r-l+i}^{r-l} ]

    我们在开头加一个( C_{r-l+1}^{r-l+1} ),这样根据( C_nm=C_{n-1}m+C_{n-1}^{m-1} ),他就可以和式子的第一项( C_{r-l+1}^{r-l} )合并为( C_{r-l+2}^{r-l+1} ),然后这个又可以可第二个合并,以此类推,最后这个式子就会合并为( C_{r-l+n+1}^{r-l+1} ),然后再减掉( C_{r-l+1}^{r-l+1}=1 )即可
    然后用lucas求这个组合数即可

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const long long N=1000010,mod=1e6+3;
    long long T,n,l,r,fac[N],inv[N];
    long long ksm(long long a,long long b)
    {
    	long long r=1;
    	while(b)
    	{
    		if(b&1)
    			r=r*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return r;
    }
    long long C(long long n,long long m)
    {
    	if(m>n)
    		return 0;
    	return fac[n]*inv[m]%mod*inv[n-m]%mod;
    }
    long long lucas(long long n,long long m)
    {
    	if(m>n)
    		return 0;
    	return n<mod?C(n,m):lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
    }
    int main()
    {
    	scanf("%lld",&T);
    	fac[0]=1,inv[0]=1;
    	for(int i=1;i<mod;i++)
    		fac[i]=fac[i-1]*i%mod;
    	inv[mod-1]=ksm(fac[mod-1],mod-2);
    	for(int i=mod-2;i>=1;i--)
    		inv[i]=inv[i+1]*(i+1)%mod;
    	while(T--)
    	{
    		scanf("%lld%lld%lld",&n,&l,&r);
    		printf("%lld
    ",(lucas(r-l+n+1,r-l+1)-1+mod)%mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    服务器搭建FTP
    VS2012 +OpenCv2.4.4配置
    python3:语法变动 及新特性
    Strlen()与sizeof()
    find命令下的atime,ctime,mtime
    C语言实现线性表
    去除zabbix calculate 模式下,有时候分母为零的情况(Cannot evaluate expression: division by zero. )
    C语言面试题汇总之一
    全局变量/静态全局变量/局部变量/静态局部变量的异同点
    MFC的自定义消息的定义与使用
  • 原文地址:https://www.cnblogs.com/lokiii/p/9806912.html
Copyright © 2020-2023  润新知