CF478D Red-Green Towers

考虑a+b的最优情况,那么最大层数刚好为:sqrt(2*(a+b))。
有可能由于a与b相差较大,则不能到达这个理论最大层数,但是没有关系,我们在dp过程中,保证当前每一步的转移是合法的,则最后倒序枚举合法的最大层数即可。
对于dp状态的解释,写在了注释中。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+5,MOD=1e9+7;
int a,b,n;
int f[2][N],sum[N];
signed main(){
	scanf("%lld%lld",&a,&b);
	n=sqrt(2*(a+b));
	f[0][0]=1;
	//假设第1层为1个,第2层为2个...
	//f[i][j]:前i层做完,共用了j个第一种颜色的方案数 
	//理论复杂度nlogn,但MOD常数较大,而我们发现,n个1e9加起来不会爆longlong
	//所以我们可以先全部累加后,再进行一次取模来卡常 
	for (register int i=1; i<=n; ++i)
	{
		int m=min(i*(i+1)/2,a);
		for (register int j=0; j<=m; ++j)
		{
			if (i<=j) f[i&1][j]+=f[(i-1)&1][j-i];
			if (i*(i+1)/2-j<=b) f[i&1][j]+=f[(i-1)&1][j];
			f[i&1][j]%=MOD;
		}
		for (register int j=0; j<=m; ++j) sum[i]+=f[i&1][j];
		sum[i]%=MOD;
		for (register int j=0; j<=m; ++j) f[(i-1)&1][j]=0;
	}
	for (register int i=n; i>=1; --i) 
	if (sum[i]) 
	{
		printf("%lld\n",sum[i]);
		break;	
	}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值