题意:定义一个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]
例如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;
}
处理边界时最好列出不等式