原题链接:
http://codeforces.com/contest/716/problem/C
题意:给你一个x,初始值等于2。给你一个k,初始值为1,求x加上j个k,能使得x+j * k满足下面两个条件:
1.x+j * k是完全平方数
2.x+j * k的平方根被k+1整除
当满足条件1,2时,k+1,求j;
思路:依照题目表意,用暴力的写法很容易得到:
#include<iostream>
#include<cmath>
using namespace std;
int n,k;
int main()
{
k=1;
n=2;
for(int i=1;i<=10000;i++)
{
for(int j=1;j<=1000;j++)
{
if(n+k*j==i&&(sqrt(i)-(int)sqrt(i)==0)&&((int)sqrt(i)%(k+1))==0)
{
k++;
cout<<i<<' '<<n<<'+'<<k<<'*'<<j<<" x="<<j<<' '<<j-jj<<endl ;
n=sqrt(i);
}
}
}
}
显然这是一个on^2的做法,一定会超时,但暴力程序得到的确实是正确的结果
所以我们可以取前几次的运行结果找规律。
4 = 2+1 * 2 ;x = 2
36 = 2+2 * 17 ;x = 17
144 = 6+3 * 46 ;x = 46
400 = 12+4 * 97 ;x = 97
900 = 20+5 * 176 ;x = 176
1764 = 30+6 * 289 ;x = 289
3136 = 42+7 * 442 ;x = 442
5184 = 56+8 * 641 ;x = 641
8100 = 72+9 * 892 ;x = 892
容易发现 从第二项开始 整个式子符合这样的规律
n*(n+1)n(n+1) = n(n-1) + nx
整理一下,得到x = n3+ 2n2+1;
ac 代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
long long ans=0;
int main()
{
long long n,m;
cin>>n;
cout<<2<<endl;
for(long long i=2;i<=n;i++)
{
cout<<i*i*i+2*i*i+1<<endl;
}
return 0;
}
显然找规律的解法不太好,因为能不能很快看出来规律很看脸。
所以赛后经过一番学习,找到了比较正统的做法(构造)。
将题目解读一下
如果要给屏幕上的x开方,我们需要满足下面几个条件
1.x+j * k是完全平方数
2.x+j * k的平方根被k+1整除
3.x+j * k显然是递增的
为了满足性质1,2 我们构造出(k+1)^2(显然这是完全平方数,而且开方后被k+1整除),为了满足性质1,3我们在(k+1) 2的基础上乘一个k 2。
所以每次可以被开方的数就是(k+1)2 * k2
这样我们就可以写出等式:
(k+1)2 * k2=x+jk;
因为每次开方后,x就等于开完方的数,所以x2应该等于上一次被开方的数,上一次能被开方的数也满足(k+1)2 * k2,只是这个k应该等于当前k-1;因为是上一级嘛;
所以我们设当前等级为k2,上一等级为k,k2=k1+1;
可以得到这样一个等式:
(k2+1)2 * k22=√(k1+1)2 * k12 + j * k2;
化简后,将k2=k1+1;代入,解得 j=k3+ 2k2+1
化简过程中,我们发现在(k+1)2的基础上乘k2是正确的,因为如果补k+1,k+整数这样,那么化简之后会出现分数,不大方便。