CF 599D SpongeBob And Squares 数列+枚举二分

题意:定义一个n*m矩阵的价值为:这个矩阵中不同正方形的个数,
例如2*3矩阵可以有 6个1*1的正方形和 2个2*2的正方形 则价值为8.
给出x,  x<=1e18. 问有多少个n*m的矩阵其价值正好为x 输出方法数和方案. 


枚举n,此时m越大显然价值越大.二分m.
n<=m时,计算一个(n,m)的价值  令p=m-n+1 
val=∑(n-i+1)*(m-i+1) [i=1..n] =∑ i*(p+i-1) [i=1..n] = ∑i*p[i=1..n] +∑i*(i-1)[i=1..n]

前半部分是个等差数列和,后半部分=n*(n+1)*(n+2)/3.所以n的上界在2e6.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>ii; 
const int N=2e6+5;
ll x,f[N];
vector<ii> v;
void Pronic()
{
	for(ll i=2;i<N;i++)
		f[i]=f[i-1]+i*(i-1);
}
ll calc(ll n,ll m)
{
	ll p=m-n+1;
	//n*m<=1e18  (p+n*p)*n/2 <=1e18
	//p(n+1)*n  <=2e18
	if(p*(n+1)>2e18/n)
		return 2e18; 
	ll tot=(p+n*p)*n/2;
	tot+=f[n];
	return tot;
}
int main()
{
	Pronic();
	cin>>x;
	for(ll n=1;n<=2000000;n++)
	{
		ll l=n,r=1e18/n+1,pos=r;
		while(l<=r)
		{
			ll mid=l+r>>1;
			ll val=calc(n,mid);
			if(val<=x)
				l=mid+1,pos=mid;
			else
				r=mid-1;	
		}
		ll val=calc(n,pos);
		if(val==x)
		{
			v.push_back(ii(n,pos));
			if(pos!=n)
				v.push_back(ii(pos,n));
		}
		else if(val>x)
			break;
	}
	sort(v.begin(),v.end());
	cout<<v.size()<<'\n';
	for(int i=0;i<v.size();i++)
		cout<<v[i].first<<' '<<v[i].second<<'\n'; 
	
	return 0;
}

处理边界时最好列出不等式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值