纪中OJ 5773 【NOIP2008模拟】简单数学题

推公式的毒瘤题

看他给的这个公式 (n-t/2)/(n-t)∈(正整数)

我们转化一下

(n-t/2)/(n-t)=x   ->    (n-t+t/2)/(n-t)=x   ->  (t/2)/(n-t)=x-1

t/(n-t)=2*(x-1)  ->     t=2*(x-1)*(n-t)     ->  t=2*(x-1)*n-2*(x-1)*t

t*(1+2*(x-1))=2*(x-1)*n   ->   t=(2*(x-1)*n)/(2*x-1)   ->   t=(  ((x-1))/(2*x-1)  )   *2*n

好了,由最后这个式子我们可以发现2*(x-1)不可能是2*x-1的倍数,所以t要是正整数,那么2*x-1一定是2*n的因数,并且它一定是奇数,然后我们就可以通过枚举它的奇数因子来得到答案,之后发现这样好像很慢?

然后我们想一想求因子的过程,小于sqrt(2*n)的因子,n除以它会得到大于sqrt(2*n)的因子,同理这个题也可以,于是我们就可以sqrt(2*n)的得到结果,时间复杂度上允许

然后看一看上面的式子怎么化简,

设当前枚举的奇数为i,那么i=2*x-1  那么2*(x-1)=i-1,那么t=(i-1)*(n/i)化简得到t=n-n/i

假如当前枚举到的数i并且它关于sqrt(2*n)的对称因子是奇数,那么令对称因子为2*n/i,和上面的同理,一样的转化,最后得到t=n-i/2

之后发现这样输出的话不满足题意的顺序,所以开一个优先队列,将求出来的t乘-1丢进去,然后最后输出时再乘-1就行了

记得开long long

代码

//By AcerMo
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
lli n;
priority_queue<lli>q;
signed main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	cin>>n;
	if (n==1) return puts("0"),0;
	for (lli i=1;i*i<2*n;i++)
	{
		if (2*n%i) continue;
		if (i%2&&(n-n/i)&&!(2*n%i)) q.push(n/i-n);
		if ((2*n/i)%2!=0&&(n-i/2)) q.push(i/2-n);  
	}
	cout<<q.size()<<" ";
	while (q.size()) cout<<-q.top()<<" ",q.pop();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/81511275