NOIP普及组蒟蒻挣扎之模拟赛C组 第四题 ——约数国の王♂

转自jzoj & c渣渣党福利

题目描述

数学的王国里,有一些约数国王……约数国王的定义是这样的:一个大于1的整数n,如果它约数的个数比1~n-1的每个整数的约数的个数都要多,那么我们就称它为约数国王。聪明的(______)在奥数书上认识了它们,于是产生了一个问题:他想知道L到R之间一共有多少个约数国王?它们分别又是谁?

输入

输入文件只有一行,包含一个l,一个r,表示小明想知道的范围。

输出

只有一行,第一个数h,表示l~r内一共有多少个约数国王,接下来h个从小到大的数(为了防止国王们打架,你需要按顺序输出。),表示约数国王分别是谁。

样例输入

1 100

样例输出

8 2 4 6 12 24 36 48 60

数据范围限制

对于30%的数据,1<=l<=r<=200000。
对于50%的数据,1<=l<=r<=500000。
对于70%的数据,保证最大的约数国王的约数的个数不大于1000。
对于100%的数据,1<=l<=r, 并且保证l,r在64位整型以内,最大的约数国王的约数的个数不大于200000。

题解 & 思路

首先很肯定的 是暴力:

#include<bits/stdc++.h>
using namespace std;
int biao[10][10] = {{0,0},{0,1},{0,2,4,8,6},{0,3,9,7,1},{0,4,6},{5,5},{6,6},{0,7,9,3,1},{0,8,4,2,6},{0,9,1}};
//手动打表模拟各位次方
int len[10] = {1,1,4,4,2,1,1,4,4,2};
int t,ans,n,a,b;
int main()
{
	//freopen("superpow.in","r",stdin);
	//freopen("superpow.out","w",stdout);
	scanf("%d",&t);
	while (t--)
	{
		ans = 1;
		scanf("%d",&n);
		for (int i = 1;i <= n;i++)
		{
			scanf("%d%d",&a,&b);
			int x = a;
			while (--b)
			{
				if (x == len[a]) x = biao[a][x];
				else x = biao[a][x % len[a]];
			}
			ans *= x;
			ans %= 10;
		}
		printf("%d\n",ans);
	}
	return 0;
}

优秀

所以说 这是一个U秀的方法

正解在此

首先我们可以知道任意一个整数都可以理解为多个素数的乘积(咀嚼一下)
辣么,我们可以得到如下公式

x = A 1 P 1 ∗ A 2 P 2 ∗ A 3 P 3 ∗ … … A k P k x = A_1 ^ {P_1} * A_2^ {P_2} *A_3^ {P_3} * ……A_k^ {P_k} x=A1P1A2P2A3P3AkPk

也就是说我们只要求这个,就是 x x x的约数个数:(全排列问题嘛, p [ i ] p[i] p[i]种情况还有 k k k它本身)

∏ k i = 1 ( P i + 1 ) \prod \frac{k}{i=1} (P_i + 1) i=1k(Pi+1)

然后显而易见,我们就能看出 一个很简单的式子

F [ i ] = m i n ( f [ k ] [ i ] ∣ 0 &lt; k ≤ ∞ ) F[i] = min(f[k][i] | 0 &lt; k \leq \infty) F[i]=min(f[k][i]0<k)

申明一个F[ ]数组,这个数组用于储存 i i i个质因子的数中最小是谁,然后我们可知这样的数组是一定存在且可被求出的。
此时提到了一个 f f f数组,又是用来干嘛呢?
其实这个数组是用来储存选择了 k k k个前质因数(如果不是前几个不一定最大,有想法可以自己证明),有i个约数的数

巴拉拉魔法能量,敲黑板

f [ k + 1 ] [ i + 1 ] = m i n ( f [ k ] [ i ] ∗ p r i m e [ k + 1 ] j ∣ 0 &lt; j ≤ ∞ ) f[k + 1][i + 1] = min(f[k][i] * prime[k + 1] ^j|0 &lt; j \leq \infty) f[k+1][i+1]=min(f[k][i]prime[k+1]j0<j)

此处的 p r i m e [ i ] prime[i] prime[i]第i个素数(抱歉,要自己打,想用现成的函数门都没得)——筛吧筛吧我的骄傲放纵

int isPrime(int n)//julao倾情贡献尊享暴力筛代码
{	
	float n_sqrt;
	if(n <= 3) return 1;
	if(n%6!=1 && n%6!=5) return 0;//julao菠萝蜜之优化
	n_sqrt=floor(sqrt((float)n));
	for(int i=5;i<=n_sqrt;i+=6) if(n%(i)==0 || n%(i+2)==0) return 0;
    return 1;
} 

有了蜜汁筛的强力加持,我们的程序便呼之欲出了——

呵呵,依然不是程序:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值