「CodePlus 2018 3 月赛」博弈论与概率统计

题面
自遗其咎。。。。。。
广义卡特兰数。
容易想到按0分时继续扣分的次数分类,
若有i次,我们来考虑恰好有i次的方案数。
然后参考这位大佬的博客
就可以发现这个东西是广义卡特兰数啊????
我怎么不去

n > m n>m n>m时很好想。
n < m n<m n<m时,注意对称点和终点在对称轴同侧的话是不能用广义卡特兰数的。

然后一波强势化简就可以利用组合数的杨辉三角性质莫队了。
A C   C o d e AC \ Code AC Code:

#include
#define maxn 500005
#define S 500
#define mod 1000000007
using namespace std;

int l[maxn],r[maxn],ans[maxn],fac[maxn]={1,1},invf[maxn]={1,1},inv[maxn]={1,1},Div[maxn],lb[maxn],c[maxn];
inline int C(int a,int b){ return 1ll * fac[a] * invf[b] % mod * invf[a-b] % mod; }
inline bool cmp(const int &u,const int &v){ return lb[u]==lb[v]?r[u]<r[v]:lb[u]<lb[v]; }

int Pow(int base,int k)
{	int ret=1;
	for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll*ret*base%mod;
	return ret;}

int main()
{
	int T,p;
	for(int i=2;i<maxn;i++)
		fac[i] = 1ll * fac[i-1] * i % mod,
		inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod,
		invf[i] = 1ll * invf[i-1] * inv[i] % mod;
	scanf("%d%d",&T,&p);
	for(int i=1;i<=T;i++) 
	{	int n,m;
		scanf("%d%d",&n,&m);
		if(n < m) l[i] = n - 1, r[i] = m + n;
		else l[i] = m - 1 , r[i] = m + n , ans[i] = 1ll * (n - m) * C(n+m,n) % mod;
		Div[i] = C(n+m,n);
		c[i] = i,lb[i] = l[i] / S;
	}
	
	sort(c+1,c+1+T,cmp);
	int sum = 1 , L=0,R=0;
	for(int i=1;i<=T;i++)
	{
		for(;R<r[c[i]];R++) sum = (2ll * sum - C(R,L)) % mod;
		for(;R>r[c[i]];) R--,sum = 1ll * (sum+C(R,L)) * ((mod+1) / 2) % mod;
		for(;L<l[c[i]];) L++ , sum = (sum + C(R,L)) % mod;
		for(;L>l[c[i]];) sum = (sum-C(R,L)) % mod , L--;
		ans[c[i]] =(ans[c[i]] + sum) % mod;
	}
	
	for(int i=1;i<=T;i++)
		printf("%lld\n",(1ll*ans[i]*Pow(Div[i],mod-2)%mod+mod)%mod);
}

你可能感兴趣的:(数论,奇巧淫技,性质分析)