F - Division or Subtraction
题意:
给你一个 N,然后让你在 [2,N] 中选某一个数字为 k,执行下列操作:
如果k ∣ N ,那么N = N / k ,否则N = N − k 。
现在问你有多少个 k,可以使得 N 最后为1。
数据范围:
2 ≤ N ≤
思路:
根据题意写几个数搞一下后,有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 需要满足 。
1.当 n = 0 时,n%k = 1,此时 k 为 n-1 的因子;
2.当 n > 0 时,只有枚举不大于 √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()的使用啊等等看到就多瞅瞅,总感觉印象不是很深刻。