【Codeforces Round 273 (Div 2)D】【DP 滚动数组】 Red-Green Towers 两种颜色积木拼搭最高锯齿楼每层颜色相同的总方案数

该博客介绍了如何使用红色和绿色积木构建红绿塔,遵循每层颜色相同且数量递减的规则。目标是找到在给定红绿积木数量下,能建造的最大高度的红绿塔的不同的构造方法数量,对10^9 + 7取模。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Red-Green Towers
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There are r red and g green blocks for construction of the red-green tower. Red-green tower can be built following next rules:

  • Red-green tower is consisting of some number of levels;
  • Let the red-green tower consist of n levels, then the first level of this tower should consist of n blocks, second level — of n - 1 blocks, the third one — of n - 2 blocks, and so on — the last level of such tower should consist of the one block. In other words, each successive level should contain one block less than the previous one;
  • Each level of the red-green tower should contain blocks of the same color.

Let h be the maximum possible number of levels of red-green tower, that can be built out of r red and g green blocks meeting the rules above. The task is to determine how many different red-green towers having h levels can be built out of the available blocks.

Two red-green towers are considered different if there exists some level, that consists of red blocks in the one tower and consists of green blocks in the other tower.

You are to write a program that will find the number of different red-green towers of height h modulo 109 + 7.

Input

The only line of input contains two integers r and g, separated by a single space — the number of available red and green blocks respectively (0 ≤ r, g ≤ 2·105r + g ≥ 1).

Output

Output the only integer — the number of different possible red-green towers of height h modulo 109 + 7.

Sample test(s)
input
4 6
output
2
input
9 7
output
6
input
1 1
output
2
Note

The image in the problem statement shows all possible red-green towers for the first sample.

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=900,M=2e5+2,Z=1e9+7,ms63=1061109567;
int n,m;
int f[2][M];	//f[][i]表示还剩下i个红色方块的方案数
void add(int &x,int y)
{
	x+=y;
	if(x>=Z)x-=Z;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		//(top+1)top<=2(n+m)
		//top+0.<=sqrt(2(n+m))
		int top=sqrt(n+m<<1);
		while((1+top)*top/2>(n+m))--top;
		int sum=0;
		int now=0;
		int nxt=1;
		MS(f[now],0);f[0][n]=1;
		for(int i=1;i<=top;++i)
		{
			MS(f[nxt],0);
			for(int red=0;red<=n;++red)//枚举之前剩下的红色的个数
			{
				int green=m+n-sum-red;//其实可以直接在for循环中使得red<+m+n-sum,或者加很多剪枝的限制条件来加速
				if(green<0)break;
				if(red>=i)add(f[nxt][red-i],f[now][red]);
				if(green>=i)add(f[nxt][red],f[now][red]);
			}
			sum+=i;
			now^=1;
			nxt^=1;
		}
		int ans=0;
		for(int red=0;red<=n;++red)add(ans,f[now][red]);
		printf("%d\n",ans);
	}
	return 0;
}
/*
【trick&&吐槽】
观察真实的数据范围,不要被很大的数字吓到了哦!

【题意】
有红绿两色的方块,数量分别为r个和g个。有0<=r,g<=2e5,r+g>=1
我们想用这红绿两色的方块(不一定全部,可以是一部分),构成一个高度尽可能高的积木块。

这个积木块需要满足——
1,假设高度为h,那么第一层有1个,第二层有2个,……,第h层有h个。
2,每层方块的颜色,不是全部为红色,就是全部为绿色。

让你输出,有多少种方案,可以构成高度最高的积木块。

【类型】
DP 滚动数组

【分析】
一定要一定要好好地分析数据规模!
这题虽然r和g的数量都可达2e5,然而,事实上可以最高达成的楼层高度,不过只有
设最高楼层的高度为top,那么,我们有——(top+1)top/2 <= n+m
显然,(top+1)top<=2(n+m),即top+0. <= 2(n+m)
显然,我们求得sqrt(2(n+m))是必然>=top的。
于是,求得一个[sqrt(2(n+m))]最为top的最大情况。
然而,这个top可能超过实际最大楼层,于是我们要有——while((1+top)*top/2>(n+m))--top;

为什么,现在的top就一定是最大楼层呢?
因为,这个楼层的搭建,总数是为1~top的和,
于是,这个划分,这个数字的拆分,可以通过极其灵活的方式搭配,于是就可以(这可是男人的直觉,哼!)
而且数量的切分上,我们是可以切出最大一层的。

于是,我们有了最大层数,而且其一定不超过899。
所以,接下来直接用f[i][j]表示现在已经搭了第1~i层,并且还剩下j块红色木块的方案数。
显然有——

1,初始条件为f[0][n]=1;
2,DP方程为
	枚举楼层,枚举之前所有楼铺完还剩下的红色木块数,然后——
	我们可以通过一共使用的木块数,求得现在还剩下的绿色木块数。
	如果现有红色木块数或者绿色木块数比铺这层楼需要的木块数多,我们就可以进行更新——
	
因为空间消耗可达900*2e5,会爆炸。
所以我们用滚动数组就可以AC啦

【时间复杂度&&优化】
O(sqrt(n+m)n)

【数据】
input
200000 200000
output
206874596

*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值