生产机器

题目链接

  • 一个合法的序列可能有多种生成方式,因此我们考虑确定其中唯一的一种
  • 从前往后匹配,只有当某种颜色的充能球的数量达到上限时才切换到下一小时
  • DP。f[i]表示考虑到第i小时,[j]表示这一小时的第一颗充能球的颜色,也是上一小时达到上限的充能球的颜色
  • 朱世杰恒等式(取的数的多少不变):$C_{m+n+1}^{n+1} =\sum_{i=0}^{m} C_{n+i}^{n} $ 可用二项式定理证
  • 不要忘记利用组合递推式“点燃引线”的思想
  • l/f中至少有一个为0的情况看起来很难处理,但相信OI美学,不妨把别扭的特判注释掉,发现答案就对了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long long jc[2000005],jcinv[2000005];
int w[100005][2];
long long f[100005][2],g[100005][2];
void pre()
{
	jc[0]=1;
	for(int i=1;i<=2000000;i++)
	{
		jc[i]=jc[i-1]*i%mod;
	}
	jcinv[2000000]=power(jc[2000000],1000000005);
	for(int i=2000000-1;i>=0;i--)
	{
		jcinv[i]=jcinv[i+1]*(i+1)%mod;
	}
}
int c(int n,int m)
{
	return jc[n]*jcinv[m]%mod*jcinv[n-m]%mod;
}
int calc(int x,int y)
{
	if(x<0||y<0)
	{
	//	return 0;
	}
	return c(x+y+1,x+1);
}
//x+1
//x+y+1
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	pre();
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>w[i][0]>>w[i][1];
		}
		long long ans=1;
		f[1][0]=(w[1][0]>0);
		f[1][1]=(w[1][1]>0);
		g[1][0]=g[1][1]=1;
		for(int i=2;i<=n;i++)
		{
			f[i][0]=(g[i-1][0]*calc(w[i-1][0]-1,w[i-1][1])%mod+g[i-1][1]*calc(w[i-1][0],w[i-1][1]-1)%mod)%mod;
			g[i][0]=f[i][0];
			f[i][0]*=(w[i][0]>0);
			f[i][1]=(g[i-1][0]*calc(w[i-1][1],w[i-1][0]-1)%mod+g[i-1][1]*calc(w[i-1][1]-1,w[i-1][0])%mod)%mod;
			g[i][1]=f[i][1];
			f[i][1]*=(w[i][1]>0);
		}
		for(int i=1;i<=n;i++)
		{
			ans=(ans+f[i][0]*(c(w[i][0]-1+w[i][1]+2,w[i][0]-1+1)-1)%mod)%mod;
			ans=(ans+f[i][1]*(c(w[i][0]+w[i][1]-1+2,w[i][0]+1)-1)%mod)%mod;
		}
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2024-08-27 22:56  D06  阅读(8)  评论(0编辑  收藏  举报