題意:
在一張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