1.题目链接。说的是滥竽充数的故事,但是抽象出来之后就是这样一个问题:原来有x*x个人,走了一个,把这x*x-1划分成N个y*y,求满足的(x,y),但是因为数量很多,所以求第k大的x,并且输出x%8191.
2.分析:根据题意我们就知道这个方程是怎么列的:x^2-Ny^2=1。就是求第k大的x。这是典型的佩尔方程,是数论种最经典的内容之一。它和线性代数里面的很多东西有着千丝万缕的关系。对于这个方程,只有在N不是完全平方数的时候有解,如果是完全平方数就无解。证明方法很简单,如果N是完全平方数,那么等式的左边可以进行因式分解,由于都是整数,所以二者乘起来不会是1。并且,一旦这个方程有解,那么就有无数组解。这也是很好证明的,就不再证了。具体的递推关系如下:
知道了这些,我们只需要把(x1,y1)算出来,我们又知道,我们研究的都是正整数解,所以根据递推式我们知道这个解是递增的,所以我们要求的第k大的元素,就是上边的那个式子,转移矩阵的k-1次幂乘初始的矩阵,这个使用矩阵快速幂就轻松搞定。所以我们首先暴力的把(x1,y1)算出来(这里有些人可能会觉得,(1,0)不是显然的是一组解吗,但是注意,我们这里研究的是正整数解,所以0是不符合的,对于N一直在变的方程,这个正整数解是不固定的,需要我们自己求解)。
void getans(ll &x, ll &y, ll d)
{
y = 1;
while (1 > 0)
{
x = (ll)sqrt(1 + d * y*y);
if (x*x - d * y*y == 1) break;
y++;
}
}
有了x1,y1.那么问题解决,AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#pragma warning(disable:4996)
//检查a是不是完全平方数
int check(int a)
{
double ans = sqrt(a);
if (ans - (int)ans == 0)
{
return 1;
}
else
{
return 0;
}
}
//函数参数输入,返回值输出
//特别注意lenth一定要改,不然每次都遍历到最大的矩阵会tle
ll lenth = 2;
ll mod= 8191;
struct Sarray
{
ll data[2][2];
//看着改
Sarray operator *(const Sarray&a)
{
Sarray tem;
for (int i = 0; i<lenth; i++)
{
for (int j = 0; j<lenth; j++)
{
for (int k = 0; k<lenth; k++)
{
tem.data[i][j] = (tem.data[i][j] + data[i][k] * a.data[k][j]) % mod;
}
}
}
return tem;
}
Sarray operator +(const Sarray&a) {
Sarray tem;
for (int i = 0; i<lenth; i++) {
for (int j = 0; j<lenth; j++) {
tem.data[i][j] = (data[i][j] + a.data[i][j]) % mod;
}
}
return tem;
}
Sarray(const Sarray&a) {
for (int i = 0; i<lenth; i++) {
for (int j = 0; j<lenth; j++) {
data[i][j] = a.data[i][j];
}
}
}
Sarray()
{
memset(data, 0, sizeof(data));
}
};
Sarray E;
void ini()
{
for (int i = 0; i<lenth; i++)
for (int j = 0; j<lenth; j++)
if (i == j)E.data[i][j] = 1;
else E.data[i][j] = 0;
}
Sarray qpow(Sarray a, int b) {
Sarray tem = E;
while (b) {
if (b & 1)tem = a * tem;
a = a * a;
b >>= 1;
}
return tem;
}
void getans(ll &x, ll &y, ll d)
{
y = 1;
while (1 > 0)
{
x = (ll)sqrt(1 + d * y*y);
if (x*x - d * y*y == 1) break;
y++;
}
}
int main()
{
ll N, K;
while (~scanf("%lld%lld", &N, &K))
{
if (check(N))
{
printf("No answers can meet such conditions\n");
}
else
{
Sarray a;
ll x1, y1;
getans(x1, y1, N);
//初始化矩阵
a.data[0][0] = x1;
a.data[0][1] = N*y1;
a.data[1][0] = y1;
a.data[1][1] = x1;
ini();
Sarray b = qpow(a, K - 1);
int xk = b.data[0][0] * x1 + b.data[0][1] * y1;
xk %= mod;
printf("%d\n", xk);
}
}
return 0;
}