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

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.
【Codeforces Round 273 (Div 2)D】【DP 滚动数组】 Red-Green Towers 两种颜色积木拼搭最高锯齿楼每层颜色相同的总方案数_第1张图片

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·105, r + 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

*/



你可能感兴趣的:(codeforces,题库-CF,动态规划-线性DP)