AtCoder - ABC 161 - F(数论)

F - Division or Subtraction

题意:

给你一个 N,然后让你在 [2,N] 中选某一个数字为 k,执行下列操作:

如果k ∣ N ,那么N = N / k ,否则N = N − k 。

现在问你有多少个 k,可以使得 N 最后为1。

数据范围:

2 ≤ N ≤ 10^{12}

思路:

根据题意写几个数搞一下后,有3种情况:
1.k 不是 n 的约数。比如:n = 7,k = 2;一直执行 n-k 的操作,如果最后结果为 1,说明这个 k可以;这个最后结果其实可以由 n%k 得出,所以如果 n%k = 1,k 成立,说明 k 满足 k 是 n-1 的因数时k成立。

2.k 是 n 的约数多次执行 k/n 后结果为 1,无余数。比如:n = 8,k = 2;无余数且结果为1,则在多次执行 n/k 后结果为 1 后,再次执行一定有 n%k = 1%k = 1也成立;判断 k 是否成立的操作是一直执行 n/k 直到余数为 1。

3.k 是 n 的约数多次执行 k/n 后结果为0,有余数。比如:n = 6,k = 2;有余数说明多次 n/k 后的 n < k,最终结果为余数;判断方法是:一直执行 n/k 操作直到 n%k!=0,判断此时的余数是否为1,是则成立,否则不成立。

根据 k 是 n 的约数时的两种情况,可以按一种方法判断 k 是否成立,首先必须保证 k 是不大于 √n的约数,然后一直执行 n/k 直到 n%k!=0 ,如果结果为 1,成立。

特判:k = 1 去掉,k = n  加上。

看到大大的更清晰的写法:
如果 n 最终能变成 1,则 k 需要满足 \frac{N}{k^{n}}%k
1.当 n = 0 时,n%k = 1,此时 k 为 n-1 的因子;
2.当 n > 0 时,只有枚举不大于 √n 的因子 k,才有可能得到\frac{N}{k^{n}}%k。 

Code:

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;

const int N = 200010;

#define int long long

int n;
set<int>st;    //用set存可以自动去重

void solve()
{
	cin >> n;
	
	//当k是n的约数时
	for (int i = 2; i * i <= n; i++)      //找到不大于√n的n的因子(因为k》=2,所以枚举因数可以从2开始)
	{
		if (n % i == 0)
		{
			int k = n;
			while (k % i == 0)k /= i;     //n一直除以因数直到不能整除为止
			if (k % i == 1)st.insert(i);  //判断此时的k-i是否为1,也就是k%i是否为余1
		}
	}

	//当k不是n的约数时
	for (int i = 1; i * i <= n - 1; i++)  //找到n-1的因子(这里从1开始枚举是因为添加n-1是用到1)
	{
		if ((n - 1) % i == 0)
		{
			st.insert(i);                 //k为n-1的因子i时,满足n一直减i,最后为1
			st.insert((n - 1) / i);       //st存因子
		}
	}

	st.erase(1);                          //将1去掉
	st.insert(n);                         //将n加上,因为n/n=1

	cout << st.size() << endl;            //最终答案为满足的k的个数
}

signed main()
{
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}

	return 0;
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
吐槽:本题注意点:

1.这是道数论题,需要多考虑逻辑性,分类讨论什么的。

2.还有set的使用,像erase()的使用啊等等看到就多瞅瞅,总感觉印象不是很深刻。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值