NOIP 2016模拟赛1 T1 最多因数
2016-10-15 23:04
302 查看
T1 最多因数
(MFactor.cpp/c/pas)
【问题描述】给两个数a,b,输出两个数之间因数个数最多的数。如果有多个因数相同的数,输出最小
的那个。
【输入格式】
两个非负整数
【输出格式】
一个整数
【样例输入】
6 10
【样例输出】
6
【样例解释】
6,8,10 都有4 个因数,但6 最小。
【数据范围】
30% 0<=a<=b<=1000
60% 0<=a<=b<=100000
100% 0<=a<=b<=2000000000, 当数据大于100000 时,保证b-a=300000
非常非常有意思的一道搜索题,很多人看到这个数据都不会想到搜索,可是实际上他就是个搜索
首先我们根据排列组合相关公式可以得到以下结论:
对于一个数,如果可以将其分解质因数p[1]^a[1] * p[2]^a[2] *.... * p[k]^a[k],那么其因数个数为:(a[1]+1)*(a[2]+1)*....*(a[k]+1)
最容易想的方法就是枚举区间的每一个数并且依次分解,这样正确性是显然的,但是只能30分(常数过大也许还没有30分)
接着分析:如果p是一个质数,那么在算n的质因数和p*n的质因数的时候,n的质因数就被算了两次,这就是时间效率不高的原因之一,因此我们考虑枚举每一个质因数来构成一个新的数,这样就避免了这种问题
但是很遗憾,这种方法仍然是会超时的,主要是因为数据范围造成的,因此只能再次优化算法
假如说当前我们通过枚举质因数得到了一个新的数k,在朴素的搜索中即使[kk*cur](cur为当前枚举的质数)与题中所给区间没有交点,搜索还是会继续进行下去,这也就是另外一个效率不高的原因,那么如何判断一个数k是否符合条件呢
很容易证明,如果(L– 1) /K< R/K,则区间内存在可以被K整除的数。因为,如果区间[L,
R]内存在可以被K整除的数,也即是从L到R中至少有一个数能被K整除,那么区间[L–
1, R]内的数被Kr除得的商肯定不止一种,所以(L– 1) /K必然小于R/K
反过来,如果(min-1)div number=max div number,则[min,max]内不存在可以被number整除的数.
题中的数据范围虽然很大,但是一个数大于sqrt(2000000000)的质因数显然最多只有一个,因此筛因数的时候只筛
到100000就差不多可以了
因此对于一个数k,如果枚举了100000以内的所有质因数都无法在[L,R]内,那么这个数一定含有一个大于100000的质因数,根据上面的公式,此时的primecnt只需乘以2即可
我们还能看到,如果当前搜索状态为(cur,k,primcnt),其中cur是指当前枚举到的质因子(按从小到大枚举),primcnt是指k中包含的约数个数。那么剩下的因子数最多为q
= [logcur(R / K)],这些因子组成的约数个数(即上述求约数个数时用到的一串乘积)最大为2q。当前所能取到的(理想情况)最大约数个数就是primcnt * 2q,如果这个数仍然无法超过当前最优解,则这一分支可以剪去。
#include<iostream> #include<cstdio> #define LL long long using namespace std; const LL maxn=100005,inf=0x3f3f3f3f; LL prime[maxn],Next[maxn],cnt,ans=inf,tot,l,r; bool vis[maxn]; void prime_table(){//线性筛质数 int i,j; for(i=2;i<=maxn;i++){ if(!vis[i])prime[++tot]=i,Next[i]=tot; for(j=1;prime[j]*i<=maxn&&j<=tot;j++){ vis[prime[j]*i]=1,Next[prime[j]*i]=j; if(i%prime[j]==0)break; } } } void search(LL cur,LL primcnt,LL num,LL L,LL R){ if(num>=1) if(primcnt>=cnt&&num>=l&&num<=r){//这个地方一定记得判断num是否在区间内,否则可能比左端点小 if(primcnt>cnt)cnt=primcnt,ans=num; else ans=min(ans,num); } LL i,t,x,xx,y,temp,curn,curt; if(L==R&&L>num)search(cur,primcnt*2,num*L,1,1);//即num含有一个大于100000的因子 for(i=cur;i<=tot;i++){//搜索的主体部分 if(prime[i]>R)return; else{ t=prime[i],x=L,y=R,xx=L-1,curn=num,temp=primcnt,curt=1; while(1){ curt++,temp+=primcnt; xx/=t,y/=t,x/=t; if(xx==y)break; curn*=t; search(i+1,temp,curn,x,y); } curt=1<<curt; if(primcnt<cnt/curt)return; } } } int main(){ LL L,R; cin>>L>>R; prime_table(); l=L,r=R; search(1,1,1,L,R); cout<<ans; }
相关文章推荐
- 【NOIP2016模拟赛No.1】 牛宫
- NOIP 2016模拟赛[八中题]题解&总结
- 【NOIP2016模拟赛No.1】 最小密度路径
- 【NOIP2016复赛模拟赛】楼层
- NOIP 2016模拟赛[nodgd题]T1 电路图1
- NOIP2016模拟赛 day6
- NOIP2016模拟赛 运 (DP+逆元)
- 【NOIP2016复赛模拟赛】朋友
- NOIP 2016模拟赛[南开题]题解&总结
- 【NOIP2016复赛模拟赛】门票
- 【NOIP2016复赛模拟赛2】侦察兵
- 【NOIP2016复赛模拟赛2】遭遇战
- 2016 NOIP模拟赛[巴蜀题]题解&&总结
- NOIP2016 模拟赛[一中题]题解&总结
- 2016 10 26考试 NOIP模拟赛 杂题
- 【NOIP2016提高A组模拟8.15】Garden
- 2016.08.17【初中部 NOIP提高组 】模拟赛C题目
- 平衡的子集 【NOIP2016提高A组集训第4场11.1】
- JZOJ4867【NOIP2016提高A组集训第8场11.5】心理学概论