您的位置:首页 > 其它

LightOJ 1341 Aladdin and the Flying Carpet 数学

2016-04-12 13:05 302 查看
题意:给个矩形的面积a,和矩形的最小边长b,问有多少种矩形的方案(不能是正方形)

分析:a可以写成x,y,因为不能是正方形,所以设x<y,那么x<sqrt(a),y>sqrt(a)

所以找到所有小于sqrt(a)的因子,看有几个大于等于b的就是方案数

因子可以由数的唯一分解定理,求得

具体 : 先筛一遍1e6以内的素数,有线性筛,然后分解a,然后dfs找所有的小于sqrt(a)的因子,

由于前12个素数的乘积大于1e12了,所以这部分复杂度,大概是O(2^12)(一般还要略大,不过大不了多少,数组要开大)左右

可以用这个估计(因为是求小于sqrt(a)的,可以除以2,当然这是空间常数)

所以这部分复杂度是O(T*2^12)满的话(4000*4000)大概也就是几百万,这部分可以忽略不计

主要的复杂度在分解素数里,因为1e6里面大概有7w多素数,这部分复杂度(最坏的情况a是大素数),大概是4000*70000,可以卡过,由于不可能都是这种数据

所以还是可以过的

吐槽:然后我看了看网上的代码,都是先求出总的,然后暴力扫b减,结果居然过了,b是sqrt(a)的级别,是百万,4000*1e6,是4e9,TLE

出题人太良心,没有卡这种的QAQ,感觉略坑啊

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1e6+5;
const int INF=0x3f3f3f3f;
int cnt;
bool v
;
LL prime[80000];
void getprime(){
for(int i=2;i*i<=N-5;++i)
if(!v[i])
for(int j=i*i;j<=N-5;j+=i)
v[j]=1;
for(int i=2;i<=N-5;++i)
if(!v[i])prime[++cnt]=i;
}
vector<LL>fac[2];
int divisors[5000],tot;
LL k;
void dfs(int pos,LL res){
if(pos==fac[0].size()){
divisors[++tot]=res;
return;
}
for(LL i=0,now=1;i<=fac[1][pos];now*=fac[0][pos],++i){
if(now*res>=k)break;
dfs(pos+1,res*now);
}
}
int main()
{
getprime();
int cas=0,T;
scanf("%d",&T);
while(T--){
printf("Case %d: ",++cas);
LL a,b;
scanf("%lld%lld",&a,&b);
k=sqrt(a);
if(k*k!=a)++k;
if(b>=k){
printf("0\n");
continue;
}
LL t=a;
fac[0].clear(),fac[1].clear();
for(int i=1;i<=cnt&&prime[i]*prime[i]<=t;++i){
if(t%prime[i])continue;
int tmp=0;
fac[0].push_back(prime[i]);
while(t%prime[i]==0)++tmp,t/=prime[i];
fac[1].push_back(tmp);
}
if(t>1){
fac[0].push_back(t);
fac[1].push_back(1);
}
tot=0;
dfs(0,1);
int ans=0;
for(int i=1;i<=tot;++i)
if(divisors[i]>=b)++ans;
printf("%d\n",ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: