2021牛客暑期多校訓練營3 E. Math(數論/韋達定理)


鏈接:https://ac.nowcoder.com/acm/contest/11254/E
來源:牛客網

題目描述

Given n, count the number of pairs of positive integers (x, y), such that xy+1∣x2+y2,1≤x≤y≤nxy+1∣x2+y2,1≤x≤y≤n.

There're t test cases in total.

輸入描述:

First line contains an integer t(1≤t≤105)t(1≤t≤105). Next t lines each contains one integer n (1≤n≤1018)(1≤n≤1018).

輸出描述:

Output t lines, denoting the answer of each testcase.

示例1

輸入

復制

10

10

100

1000

10000

100000

114514

1919810

20190104

123123123123

10000001000000

輸出

復制

2
5
14
31
65
67
158
326
5226
22091

看了dls的題解悟了半天貌似懂了(有錯請指正

當然這個題可以打表找規律(找到了但沒完全找到)。

\(xy+1|x^2+y^2\),不妨設\(k(xy+1)= x^2 + y^2\ 且\ x\leq y\)。如果固定x不變,可以將方程寫為:\(y^2-kxy+x^2-k=0\)。由高中學過的韋達定理,這個方程的兩個解為\(y_1 = \frac{kx+\sqrt {k^2x^2-4(x^2-k)}}{2}, y_2 = \frac{kx-\sqrt {k^2x^2-4(x^2-k)}}{2}\)。因此\(y_1 + y_2 = kx, y_1 y_2=x^2-k\)不妨設\(y_1\)是一開始那個解\(y\),則\(y_2\)這個解更小(因為\(y_1 > x\)\(y_1 y_2 = x^2-k\),若\(y_2\)更大則顯然不可能)且非負(如果是負數,帶入原方程會矛盾)。所以此時有\(k(xy_2+1)= x^2 + y_2^2\ 且\ y_2\leq x \ 且\ y_2=kx-y1\)。這時候把\(y_2\)看做\(x\)\(x\)看做\(y\)(統一成原來方程的形式),就可以發現這樣可以不斷進行遞降,且由一開始\((x, y)\)這組解遞降得到的解\((kx-y, x)\)\(kx-y\leq x\)。因此對於這個k,絕對值最小的一組正整數解一定滿足\(kx-y=0\)(因為要求是正整數解,而0到\(y\)的正整數個數是有限的,不是0的話就沒有出口了)。此時\(y=kx\)(注意這里的x和y並不是一開始的,僅僅是描述最終的解的形式),帶入原方程得到\(x^2+k^2x^2=k^2x^2+k\),即\(x^2=k\)。因此設最終那組解里最小的數為\(x\),則\(y = kx=x^2x=x^3\),解為\((x,x^3)\)。由於這個解是遞降得到的,因此可以逆推回去。設\(x=kx'-y',y=x'\)(這里的y是\(x^3\),\(k\)\(x^2\)不變),則前一組解\((x', y')=(x^3,x^5-x)\)。這樣不斷倒推回去就能得到由一個初始的x推出來的所有的解了。對於這個題而言,需要進行預處理,預處理的時候枚舉的是絕對值最小的一組正整數解的x,然后對於所有的解\((x, y)\),把\(y\)放入一個vector並排序,對於每次詢問直接在集合中upper_bound二分查找n,則這個位置之前的數的個數就是答案。因為1e18開三次根為1e6,枚舉的時候枚舉到1e6即可。

#include <bits/stdc++.h>
using namespace std;
//int128
int main() {
	vector<long long> b;
	b.push_back(1ll);
	for(long long xx = 2; xx <= 1000000; xx++) {
		//cout << xx << endl;
		long long x = 1ll * xx, y = 1ll * xx * xx * xx, k = xx * xx;
		while(true) {
			b.push_back(y);
			if(__int128(k) * __int128(y) - __int128(x) > (1e18+5)) {
				break;
			}
			long long t = y;
			y = k * y - x;//倒推回去的下一個解的y
			x = t;
		}
	}
	sort(b.begin(), b.end());
	int t;
	cin >> t;
	while(t--) {
		//cout << t << endl;
		long long n;
		cin >> n;
		long long pos = upper_bound(b.begin(), b.end(), n) - b.begin();
		cout << pos << endl;
	}

	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM