2021-08-12校网比赛D题 [数学][推柿子]

在这里插入图片描述

x 2 = k n + 1 x^2=kn+1 x2=kn+1
移项发现是个平方差
( x + 1 ) ( x − 1 ) = k n (x+1)(x-1)=kn (x+1)(x1)=kn
考 虑 拆 解 k , n k,n k,n
( x + 1 ) = k 1 ∗ n 1 (x+1)=k_1*n_1 (x+1)=k1n1
( x − 1 ) = k 2 ∗ n 2 (x-1)=k_2*n_2 (x1)=k2n2
k 1 ∗ k 2 = k , n 1 ∗ n 2 = n k_1*k_2=k,n_1*n_2=n k1k2=k,n1n2=n
发现可以枚举 n n n 的约数 y y y
记作其中的 n 1 n_1 n1
则有 n 2 = n / y n_2=n/y n2=n/y, ( x + 1 ) = k 1 ∗ y (x+1)=k1*y (x+1)=k1y
因为 x < n x<n x<n, x + 1 < = n x+1<=n x+1<=n,考虑枚举倍数 k 1 k_1 k1
假设当前枚举倍数为 d d d
则有 ( x + 1 ) = d ∗ y (x+1)=d*y (x+1)=dy
x = d ∗ y − 1 x=d*y-1 x=dy1
④⑤带入②,则有 ( d ∗ y − 2 ) = k 2 ∗ ( n / y ) (d*y-2)=k_2*(n/y) (dy2)=k2(n/y)
( d ∗ y − 2 ) (d*y-2) (dy2) ( n / y ) (n/y) (n/y) 的倍数,则 x = d ∗ y − 1 x=d*y-1 x=dy1 为一组符合的解

同理可以将 y y y 记作其中的 n 2 n_2 n2,即由②推①
则有 ( d ∗ y + 2 ) = k 1 ∗ ( n / y ) (d*y+2)=k1*(n/y) (dy+2)=k1(n/y)
( d ∗ y + 2 ) (d*y+2) (dy+2) ( n / y ) (n/y) (n/y) 的倍数,则 x = d ∗ y + 1 x=d*y+1 x=dy+1 为一组可能的解,
因为这里是 ( x − 1 ) − > ( x + 1 ) (x-1)->(x+1) (x1)>(x+1) x x x 可能大于 n n n

p s : ps: ps:

  1. 一组约数 y y y , n / y n/y n/y,可能对应两个解
    y − > x − 1 , ( n / y ) − > x + 1 y->x-1,(n/y)->x+1 y>x1,(n/y)>x+1 或者 y − > x + 1 , ( n / y ) − > x − 1 y->x+1,(n/y)->x-1 y>x+1,(n/y)>x1
  2. 枚举倍数时,选择大于 n \sqrt{n} n 的,
    不然 ∑ ( k i ) \sum(k_i) (ki) 可能和会很大
    然后对于每个枚举的 约数,
    可以 ( x − 1 ) − > ( x + 1 ) (x-1)->(x+1) (x1)>(x+1) 或者 ( x + 1 ) − > ( x − 1 ) (x+1)->(x-1) (x+1)>(x1)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>

using namespace std;

typedef long long ll;

const int N = 1e6 + 10;
ll n, ans[N], num, cnt; 
  
void Jud(ll y) 
{
	for (ll d = 0; d <= n / y; d++) 
	{
		num = (d * y - 2);
		if (!(num % (n / y))) ans[++cnt] = d * y - 1;		
		num = (d * y + 2);
		if (!(num % (n / y))) ans[++cnt] = d * y + 1;
	}
}

int main() {
	scanf("%lld", &n);
	if (n == 1) { printf("None\n"); return 0; }
	ll siz = sqrt(n);
	for(ll i = 1; i <= siz; i++) if (!(n % i)) Jud(n / i);
	sort(ans + 1, ans + cnt + 1);
	int m = unique(ans + 1, ans + cnt + 1) - ans - 1;
	int l = 1, r = m;
	while (ans[r] >= n) r--;
	while (ans[l] < 0) l++; 
	if (!(r - l + 1)) printf("None");
	else for(int i = l; i <= r; i++) printf("%lld\n", ans[i]);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值