题意:
在一张3*5的网格图中,有15个1*1的矩阵,有8个2*2的矩阵,有3个3*3的矩阵,一共有26个不同的正方形。
现在已知一个矩形中包含一定数量的正方形,问这个矩形有多少种不同的可能。
Input
第一行包含一个整数 x (1 ≤ x ≤ 1018) — 表示矩形中包含的正方形个数。
Output
输出整数k表示有多少种不同的矩形满足条件
之后输出 k 对整数,每对整数描述一个矩形。按照 n 递增的顺序输出。
Example
Input
26
Output
6 1 26 2 9 3 5 5 3 9 2 26 1
Input
2
思路:
假设行数是k时,总共的格子数是m,我们的目标是找列的长度设为n(k<=n,因为k>n的时候其实在之前出现过)。首先只有一个格子的有k*n个,两个格子的有(k-1)*(n-1)个
三个格子的有(k-2)*(n-2)...把他们展开加和就能得到等式k*k*n-sum(k-1)(k+n)+sum2(k-1)=m,这里的sum(n)代表前n项的和,sum2(n)代表前n项的平方和。然后一化简就得到另一个数为(m-sum2(k-1)+sum(k-1)*k)/(k*k-sum(k-1))。代入k=1e6,m=1e18时测试,发现这时候k和n已经非常接近,所以直接暴力枚举就可以,然后用上面公式求出结果。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<unordered_map>
#define mod (1000000007)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=1e5+10;
struct node{
ll l,r;
}ans[2000000];
ll sum(ll x){ return (x+1)*x/2; }
ll sum2(ll x){ return x*(x+1)*(x+x+1)/6; }
int main(){
ll m,k,cnt=0;
scanf("%lld",&m);
for(ll k=1;;k++){
ll t1=(m-sum2(k-1)+sum(k-1)*k);
ll t2=(k*k-sum(k-1));
ll tmp=t1/t2;
if(tmp<k) break;
if(tmp*t2==t1){
ans[cnt].l=k;ans[cnt++].r=tmp;
}
}
printf("%d\n",cnt*2-(ans[cnt-1].l==ans[cnt-1].r));
for(int i=0;i<cnt;i++){
printf("%lld %lld\n",ans[i].l,ans[i].r);
}
if(ans[cnt-1].l!=ans[cnt-1].r) printf("%lld %lld\n",ans[cnt-1].r,ans[cnt-1].l);
for(int i=cnt-2;i>=0;i--)
printf("%lld %lld\n",ans[i].r,ans[i].l);
return 0;
}
//k
//k*k*n-sum(k-1)(k+n)+sum2(k-1)=m
//tmp=(m-sum2(k-1)+sum(k-1)*k)/(k*k-sum(k-1))另一个数
//
//k*n (k-1)*(n-1) (k-2)(n-2)
//k*n kn-k-n+1 kn-2k-2n+4
//1 n
//2 2*n+1
//3 4n-4