题意:给个矩形的面积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,感觉略坑啊
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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 "); 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 ",ans); } return 0; }