zoukankan      html  css  js  c++  java
  • 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 且 xleq 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_2leq x 且 y_2=kx-y1)。这时候把(y_2)看做(x)(x)看做(y)(统一成原来方程的形式),就可以发现这样可以不断进行递降,且由一开始((x, y))这组解递降得到的解((kx-y, x))(kx-yleq 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;
    }
    
  • 相关阅读:
    【每日一题】740. 删除并获得点数
    【每日一题】1473. 粉刷房子 III
    【每日一题】7. 整数反转
    【每日一题】554. 砖墙
    【每日一题】690. 员工的重要性
    【每日一题】137. 只出现一次的数字 II
    【每日一题】403. 青蛙过河
    【每日一题】633. 平方数之和
    【每日一题】938. 二叉搜索树的范围和
    a_lc_到达终点(数学优化)
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/15056850.html
Copyright © 2011-2022 走看看