LightOJ 1341 Aladdin and the Flying Carpet 数学

题意:给个矩形的面积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[N];
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

 

          

       

posted @ 2016-04-12 13:05  shuguangzw  阅读(220)  评论(2编辑  收藏  举报