AtCoder Beginner Contest 161 F Division or Substraction 打表+找规律+数论

AtCoder Beginner Contest 161   比赛人数9927  快,比赛开始后5分钟看到所有题

AtCoder Beginner Contest 161 F  Division or Substraction   打表+找规律+数论

总目录详见https://blog.csdn.net/mrcrack/article/details/104454762

在线测评地址https://atcoder.jp/contests/abc161/tasks/abc161_f

样例模拟如下

6

3

2:6/2=3,3-2=1选
3:6/3=2不选
4:6-4=2不选
5:6-5=1选
6:6/6=1选



为了获得更多的数据,编写了打表代码,如下

#include <stdio.h>
#define LL long long
int judge(LL x,LL n){
	while(n>=x){
		if(n%x==0)n/=x;
		else n-=x;
	}
	if(n==1)return 1;
	else return 0;
}
int main(){
	LL i,n,k,j;
	scanf("%lld",&n);
	for(i=2;i<=n;i++){
		printf("%lld\n",i);
		for(j=2;j<=i;j++)
			if(judge(j,i))printf("%lld ",j);
		printf("\n\n");
	}
	return 0;
}

编译上述打表代码,运行,输入100,获得了输出数据如下

2
2 

3
2 3 

4
2 3 4 

5
2 4 5 

6
2 5 6 

7
2 3 6 7 

8
2 7 8 

9
2 3 4 8 9 

10
2 3 9 10 

11
2 5 10 11 

12
2 3 11 12 

13
2 3 4 6 12 13 

14
2 13 14 

15
2 7 14 15 

16
2 3 4 5 15 16 

17
2 4 8 16 17 

18
2 17 18 

19
2 3 6 9 18 19 

20
2 4 19 20 

21
2 3 4 5 10 20 21 

22
2 3 7 21 22 

23
2 11 22 23 

24
2 23 24 

25
2 3 4 5 6 8 12 24 25 

26
2 5 25 26 

27
2 3 13 26 27 

28
2 3 9 27 28 

29
2 4 7 14 28 29 

30
2 3 5 29 30 

31
2 3 5 6 10 15 30 31 

32
2 31 32 

33
2 4 8 16 32 33 

34
2 3 11 33 34 

35
2 17 34 35 

36
2 3 4 5 6 7 35 36 

37
2 3 4 6 9 12 18 36 37 

38
2 37 38 

39
2 3 19 38 39 

40
2 3 13 39 40 

41
2 4 5 8 10 20 40 41 

42
2 6 41 42 

43
2 3 6 7 14 21 42 43 

44
2 43 44 

45
2 4 11 22 44 45 

46
2 3 5 9 15 45 46 

47
2 23 46 47 

48
2 3 47 48 

49
2 3 4 6 7 8 12 16 24 48 49 

50
2 7 49 50 

51
2 5 10 25 50 51 

52
2 3 4 17 51 52 

53
2 4 13 26 52 53 

54
2 53 54 

55
2 3 5 6 9 18 27 54 55 

56
2 5 7 11 55 56 

57
2 3 4 7 8 14 28 56 57 

58
2 3 19 57 58 

59
2 29 58 59 

60
2 59 60 

61
2 3 4 5 6 10 12 15 20 30 60 61 

62
2 61 62 

63
2 3 31 62 63 

64
2 3 4 7 8 9 21 63 64 

65
2 4 8 16 32 64 65 

66
2 3 5 13 65 66 

67
2 3 6 11 22 33 66 67 

68
2 4 67 68 

69
2 4 17 34 68 69 

70
2 3 23 69 70 

71
2 5 7 10 14 35 70 71 

72
2 8 71 72 

73
2 3 4 6 8 9 12 18 24 36 72 73 

74
2 73 74 

75
2 3 37 74 75 

76
2 3 5 15 25 75 76 

77
2 4 19 38 76 77 

78
2 6 7 11 77 78 

79
2 3 6 13 26 39 78 79 

80
2 4 5 79 80 

81
2 3 4 5 8 9 10 16 20 40 80 81 

82
2 3 9 27 81 82 

83
2 41 82 83 

84
2 3 4 83 84 

85
2 3 4 6 7 12 14 21 28 42 84 85 

86
2 5 17 85 86 

87
2 43 86 87 

88
2 3 29 87 88 

89
2 4 8 11 22 44 88 89 

90
2 3 9 89 90 

91
2 3 5 6 9 10 15 18 30 45 90 91 

92
2 7 13 91 92 

93
2 3 4 23 46 92 93 

94
2 3 31 93 94 

95
2 47 94 95 

96
2 5 19 95 96 

97
2 3 4 6 8 12 16 24 32 48 96 97 

98
2 97 98 

99
2 7 14 49 98 99 

100
2 3 4 9 10 11 33 99 100 

思路摘自https://www.cnblogs.com/zcr-blog/p/12634639.html

手工模拟如下

100
2 3 4 9 10 11 33 99 100
 
以上面数据作为说明
2<=k<=100
1.不是100的约数,那么是100-1=99的约数
k可取3,33,9,11,99
2.是100的约数,
备选数据有2,50,4,25,5,20,10,100
2:100/2=50,50/2=25,25%2=1选
50:100/50=2不选
4:100/4=25,25%4=1选
25:100/25=4不选
5:100/5=20,20/5=4不选
20:100/20=5不选
10:100/10=10,10/10=1选
100:100/100=1选
k可取2,4,10,100

综合两种情况,k可取3,33,9,11,99,2,4,10,100

1 不是 n的约数

这种情况比较简单,不是 n的约数根据题意 n 会一直减 k,减到 n<k。

最后得到的其实就是 n模k。

我们需要找的其实就是所有 k使得 n模k=1。

这其实就是 n−1的约数,所以直接查询 n−1 的约数(不包括1)个数即可。时间复杂度:O(√n)

k不是n的约数,是n-1的约数,证明如下:

n%k=1,即n=kx+1,x是整数,故n-1=kx,可得(n-1)%k=0,k是n-1的约数

2 是 n的约数

这种情况其实更好想。

我们首先要找到所有约数(不包括1),这样做的复杂度是O(√n)

根据题目要求我们要不断的除以这个约数,而因为 k≥2所以这是O(logn)的。

而当它不整除时,就变成了1,得到的会是 n模k(此时的 n 应是除以 k 若干遍后的 n),如果 n模k==1 则 ans++。

总复杂度 O(√nlog√n)。

记得 n一定是一个满足条件的 k。

记住要特判“2”。

这两种情况不存在相同的因子,因为相邻自然数互质。(摘自https://www.cnblogs.com/st1vdy/p/12634767.html)

AC代码如下

#include <stdio.h>
#define LL long long
LL n,cnt;
int judge(LL k,LL m){
	while(m>=k){
		if(m%k==0)m/=k;
		else m%=k;
	}
	if(m==1)return 1;
	else return 0;
}
int main(){
	LL i;
	scanf("%lld",&n);
	if(n==2){printf("1\n");return 0;}//注意n=2需特判
	for(i=2;i*i<=n-1;i++)//找n-1的约数
		if((n-1)%i==0){
			cnt++;
			if(i!=(n-1)/i)cnt++;
		}
	cnt++;//加上n-1本身
	for(i=2;i*i<=n;i++)
		if(n%i==0){
			if(judge(i,n))cnt++;
			if(i!=n/i&&judge(n/i,n))cnt++;
		}
	cnt++;//加上n本身
	printf("%lld\n",cnt);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值