LightOJ 1341 - Aladdin and the Flying Carpet(唯一分解定理)
It’s said that Aladdin had to solve seven mysteries before getting the Magical Lamp which summons a powerful Genie. Here we are concerned about the first mystery.
Aladdin was about to enter to a magical cave, led by the evil sorcerer who disguised himself as Aladdin’s uncle, found a strange magical flying carpet at the entrance. There were some strange creatures guarding the entrance of the cave. Aladdin could run, but he knew that there was a high chance of getting caught. So, he decided to use the magical flying carpet. The carpet was rectangular shaped, but not square shaped. Aladdin took the carpet and with the help of it he passed the entrance.
Now you are given the area of the carpet and the length of the minimum possible side of the carpet, your task is to find how many types of carpets are possible. For example, the area of the carpet 12, and the minimum possible side of the carpet is 2, then there can be two types of carpets and their sides are: {2, 6} and {3, 4}.
Input
Input starts with an integer T (≤ 4000), denoting the number of test cases.
Each case starts with a line containing two integers: a b (1 ≤ b ≤ a ≤ 1012) where a denotes the area of the carpet and b denotes the minimum possible side of the carpet.
Output
For each case, print the case number and the number of possible carpets.
Sample Input
2
10 2
12 2
Sample Output
Case 1: 1
Case 2: 2
据说阿拉丁必须先解决七个谜团,然后才能获得召唤强大精灵的魔法灯。在这里,我们关注第一个谜。
阿拉丁正要进入一个魔幻洞穴,由邪恶的巫师率领,他伪装成阿拉丁的叔叔,在入口处发现了一块奇怪的魔毯。有一些奇怪的生物守护着洞穴的入口。阿拉丁可以逃跑,但他知道被抓住的可能性很高。因此,他决定使用神奇的飞毯。地毯是矩形的,但不是正方形的。阿拉丁拿下地毯,在地毯的帮助下,他穿过了入口。
现在,您将获得地毯的面积以及地毯最小可能边的长度,您的任务是找到可能的地毯类型。例如,地毯12的面积以及地毯的最小可能侧面是2,那么可以有两种类型的地毯,它们的侧面是:{2,6}和{3,4}。
输入
输入以整数T(≤4000)开头,表示测试用例的数量。
每种情况都从包含两个整数的行开始:a b(1≤b≤a≤1012)其中a表示地毯的面积,b表示地毯的最小可能边。
输出
对于每种情况,请打印箱号和可能的地毯数。
样本输入
2
10 2
12 2
样本输出
Case 1: 1
Case 2: 2
题目大意:
输入一个t,表示有 t 组测试样例,对于每组测试样例,输入a和b,a表示地毯的面积,b表示地毯的最小边长,求地毯边长的可能方案数。
解题思路:
这个题求的是方案数,我们可以抽象成求因子的个数,先不考虑b,拿a=12为例,要想拼成面积为12的地毯,边长可能是1 12 、2 6、3 4、6种边长,对应3种方案,也就是说12有6个因子,方案数等于因子数/2,范围有1e12,拿根号n的话也会超时的,我们需要了解一下唯一分解定理:
(1)一个大于1的正整数N,如果它的标准分解式为: ,那么它的正因数个数为
个。
其中p1,p2…是该数的质因子,所以对于这个题而言,我们可以先打一个1e6的素数表(1e12开方),之后再用一个数组存储每一个出现过的素数,在对a分解质因子的同时求出因子的个数,最后/2即可。需要注意的是:他有一个最小边长b,我们从1遍历到b,只要是a的因子,ans–即可。一开始的时候特判一下,b x b是否<=a,如果b*b>a则ans一定为0。上AC代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
using ll = long long;
const int _max=1e6+50;
bool book[_max];
ll prime[_max],cnt=0;
ll a,b;
void init()//埃氏筛素数
{
memset(book,false,sizeof book);
for(int i=2;i<_max;i++)
{
if(!book[i])
{
prime[cnt++]=i;
for(int j=i*2;j<_max;j+=i)
book[j]=true;
}
}
}
ll solve(ll a)
{
ll sum=1;
for(int i=0;i<cnt&&prime[i]*prime[i]<=a;i++)
{
if(a%prime[i]==0)
{
int s=0;
while(a%prime[i]==0)
{
s++;
a/=prime[i];
}
sum*=(1+s);//唯一分解定理的应用,求因子的总数
}
}
if(a>1)//判断一下是否有没分解完的因子
sum*=2;
return sum;
}
int main()
{
ios::sync_with_stdio(false);
int t,k=1;
cin>>t;
init();
while(t--)
{
cin>>a>>b;
if(a<b*b)//特判一下,因为这里TLE了一次。
{
cout<<"Case "<<k++<<": "<<0<<endl;
continue;
}
ll ans=solve(a);
ans/=2;
for(int i=1;i<b;i++)
{
if(a%i==0)
ans--;
}
cout<<"Case "<<k++<<": "<<ans<<endl;
}
//system("pause");
return 0;
}