【Codeforces Round 332 (Div 2)D】【数学 公式推导】Spongebob and Squares 正方形数量恰好为x个的所有大矩形

D. Spongebob and Squares
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Spongebob is already tired trying to reason his weird actions and calculations, so he simply asked you to find all pairs of n and m, such that there are exactly x distinct squares in the table consisting of n rows and m columns. For example, in a 3 × 5 table there are 15squares with side one, 8 squares with side two and 3 squares with side three. The total number of distinct squares in a 3 × 5 table is15 + 8 + 3 = 26.

Input

The first line of the input contains a single integer x (1 ≤ x ≤ 1018) — the number of squares inside the tables Spongebob is interested in.

Output

First print a single integer k — the number of tables with exactly x distinct squares inside.

Then print k pairs of integers describing the tables. Print the pairs in the order of increasing n, and in case of equality — in the order of increasing m.

Sample test(s)
input
26
output
6
1 26
2 9
3 5
5 3
9 2
26 1
input
2
output
2
1 2
2 1
input
8
output
4
1 8
2 3
3 2
8 1
Note

In a 1 × 2 table there are 2 1 × 1 squares. So, 2 distinct squares in total.

In a 2 × 3 table there are 6 1 × 1 squares and 2 2 × 2 squares. That is equal to 8 squares in total.



#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=1e6,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
LL x;
//pair<LL,LL>a[N];int g;
set< pair<LL,LL> >sot;
int main()
{
	//m=(2*(x-前(n-1)项的sqrsum))/n+n*(n-1))/(n+1)
	while(~scanf("%llu",&x))
	{
		sot.clear();//g=0;
		LL sqrsum=0;
		for(LL n=1;;++n)
		{
			if(sqrsum>x)break;
			LL tmp=(x-sqrsum)*2;
			if(tmp%n==0)
			{
				tmp=tmp/n+n*(n-1);
				if(tmp%(n+1)==0)
				{
					LL m=tmp/(n+1);
					if(n<=m)
					{
						//a[++g]=MP(n,m);
						//if(n!=m)a[++g]=MP(m,n);
						sot.insert(MP(n,m));
						sot.insert(MP(m,n));
					}
				}
			}
			sqrsum+=n*n;
		}
		printf("%d\n",sot.size());
		for(set< pair<LL,LL> >::iterator it=sot.begin();it!=sot.end();++it)printf("%llu %llu\n",it->first,it->second);
		//printf("%d\n",g);sort(a+1,a+g+1);
		//for(int i=1;i<=g;++i)printf("%lld %lld\n",a[i].first,a[i].second);
	}
	return 0;
}
/*
【trick&&吐槽】
我们一开始定义n<=m,不代表求出来的就满足n<=m。
比如对x==2,n==2时,m=(2*(x-前(n-1)项的sqrsum))/n+n*(n-1))/(n+1)=1。
如果不是用set判重的话,我们需要判定n<=m这个条件。

【题意】
数学

【类型】
给你一个x,让你求出所有的矩形,使得该矩形内正方形的数量恰好为x。
矩形内正方形的数量这样定义——
假如说矩形的长为n*m,并使得n<=m,那么矩形内有——
1*1的正方形有n*m个
2*2的正方形有(n-1)*(m-1)个
3*3的正方形有(n-2)(m-2)个
n*n的正方形有(n-n+1)*(m-n+1)个
即:(n*m)+(n-1)*(m-1)+(n-2)*(m-2)+(n-3)*(m-3)+...+(n-n+1)*(m-n+1)的总和恰好为x

【分析】
做这种数学类的,公式推理性质比较强的题目,一定要保证自己的公式推理严谨认真不出错。
我们这题的公式为(n*m)+(n-1)*(m-1)+(n-2)*(m-2)+(n-3)*(m-3)+...+(n-n+1)*(m-n+1)==x。
这里的n为矩形长与宽的较小值,公式化简一下,变成了——n*n*m+1*1+2*2+3*3+...+(n-1)*(n-1)-(1+2+3+...+n-1)(n+m)==x。
而x^2的前n项和的公式是n(n+1)(2n+1)/6。所以n的上限也不过只有sqrt(6e18)级别。
于是我们暴力枚举n,然后得到n*n*m-(1+2+3+...+n-1)(n+m)==x-(1*1+2*2+3*3+...+(n-1)*(n-1))。
为了化简,我们把(1+2+3+...+n-1)写成公式的形式,即n*n*m-(n*(n-1))/2*(n+m)==x-(1*1+2*2+3*3+...+(n-1)*(n-1))
我们左右同时除以一个n,得到n*m-(n-1)(n+m)/2==(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n
然后左边拆开,得到n*m-(n*n-n+n*m-m)/2==(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n
发现两边还是同时乘以一个2的好,于是得到2*n*m-(n*n-n+n*m-m)==2*(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n
再化简,得到2*n*m-n*n-n*m+n+m==2*(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n
即(n+1)*m==2*(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n+n*n-n
即m=(2*(x-(1*1+2*2+3*3+...+(n-1)*(n-1)))/n+n*(n-1))/(n+1)
于是我们就可以求得m,要求m>=n

【时间复杂度&&优化】
O(nlogn)

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值