poj3421
题目链接:https://vjudge.net/problem/POJ-3421
一开始直接把约数全部枚举出来,求LIS,结果一直tle......明明900000的时候约数个数才100+,用LIS应该没问题,可能是数据组数很多?后来用质因数分解,复杂度确实降下来很多,因为主要的复杂度在分解质因数上,这几乎可以忽略不计。设n=p1^a1*p2^a2*...*pk^ak,则长度len=a1+...ak,考虑将k种len个素数排列,逐个乘得到链。如果两个排列不同,则链不同。(例如排列为2 2 5 5,链为2 4 20 100),那么方案数等价于求有重复元素的全排列,则ans=(len)!/(a1!*a2!*...*ak!);
1 #include<cstdio> 2 #include<cstring> 3 #define ll long long 4 using namespace std; 5 const int maxn=1100000+10; 6 int p[maxn],pr[maxn],num[100]; 7 int n,i,j,k,len,ans,t,m,s; 8 ll tmp; 9 10 ll fac(int x){if (x==1) return 1;else return x*fac(x-1);} 11 12 int main(){ 13 t=0; 14 for (i=2;i<maxn;i++) 15 if (p[i]==0){ 16 pr[++t]=i; 17 for (j=i+i;j<maxn;j+=i) p[j]=1; 18 } 19 while (~scanf("%d",&n)){ 20 k=0; 21 memset(num,0,sizeof(num)); 22 for (i=1;i<=t;i++){ 23 if (n==1) break; 24 if (p[n]==0) { 25 k++;num[k]++;break; 26 } 27 if (n%pr[i]==0){ 28 k++; 29 while (n%pr[i]==0){ 30 n/=pr[i];num[k]++; 31 } 32 } 33 } 34 len=0;ans=1;tmp=1; 35 for (i=1;i<=k;i++) len+=num[i]; 36 for (i=1;i<=k;i++) tmp*=fac(num[i]); 37 ans=fac(len)/tmp; 38 printf("%d %d ",len,ans); 39 } 40 return 0; 41 }
poj3292
题目链接:https://vjudge.net/problem/POJ-3292
用类似埃氏筛的方法求出1到1000001的所有H素数,再用f[i]表示前i个数中有多少半素H数。判断一个数是不是半素H数一开始tle了,后来加了个判断条件就过了:注意半素的H数只有两个除了本身的H素因子(可重复)。所以验证一个数a是不是半素H数,只要找到一个是它的约数的H素数b,判断a/b是不是H素数即可,然后break
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 const int maxn=1000+10; 5 int pr[maxn],p[maxn],f[maxn]; 6 int n,t,i,j,k,b; 7 8 int main(){ 9 memset(p,0,sizeof(p)); 10 t=0; 11 for (i=1;i<=4;i++) p[i]=1; 12 for (i=5;i<maxn;i++){ 13 if (i%4!=1) { 14 p[i]=1;continue; 15 } 16 if (p[i]==0){ 17 pr[++t]=i;k=5; 18 while (i*k<maxn){ 19 p[i*k]=1;k+=4; 20 } 21 } 22 } 23 memset(f,0,sizeof(f)); 24 for (i=1;i<maxn;i++){ 25 if (i%4!=1||(i%4==1&&p[i]==0)) { 26 f[i]=f[i-1];continue; 27 } 28 for (j=1;j<=t;j++) 29 if (i%pr[j]==0){ 30 k=i/pr[j]; 31 if (p[k]==0) f[i]=f[i-1]+1; else f[i]=f[i-1]; 32 break; 33 } 34 } 35 cin>>n; 36 while (n!=0){ 37 cout<<n<<' '<<f[n]<<endl;cin>>n; 38 } 39 return 0; 40 }
poj2689
题目链接:https://vjudge.net/problem/POJ-2689
区间筛法,来自于挑战程序设计竞赛P120。注意到一个合数n有小于等于根号n的素因子,所以先把1到2^16的所有素数预处理出来(程序实际预处理了1到100000的),之后用这些素数来筛区间[l,u]。程序中,pr[j-l]=0表示j为素数;筛大区间[l,u]时起始点k加了一个特判,因为有可能起始点为素数。此外要开long long,并且注意l=1时pr[0]=1的特(坑)殊(比)情况。
1 #include<cstdio> 2 #include<cstring> 3 #define ll long long 4 using namespace std; 5 const int maxm=100000+10; 6 const int maxn=1000000+10; 7 ll p[maxn],pr[maxn],ans[maxn]; 8 ll l,u,i,j,k,d,x,y; 9 10 int main(){ 11 memset(p,0,sizeof(p)); 12 for (i=2;i<maxm;i++) 13 if (p[i]==0){ 14 for (j=i+i;j<maxm;j+=i) p[j]=1; 15 } 16 while (~scanf("%lld%lld",&l,&u)){ 17 memset(pr,0,sizeof(pr)); 18 for (i=2;i*i<=u;i++) 19 if (p[i]==0){ 20 k=(l%i==0)?l:(l/i+1)*i; 21 if (k==i) k+=i; //* 22 for (j=k;j<=u;j+=i) pr[j-l]=1; //pr[j-l]=0表示j是素数 23 } 24 int num=0; 25 if (l==1) pr[0]=1; //* 26 for (i=0;i<=u-l;i++) if (pr[i]==0) ans[++num]=i+l; 27 if (num<=1){ 28 printf("There are no adjacent primes. ");continue; 29 } 30 d=maxn; 31 for (i=1;i<num;i++) 32 if (ans[i+1]-ans[i]<d){ 33 d=ans[i+1]-ans[i]; 34 x=ans[i];y=ans[i+1]; 35 } 36 printf("%lld,%lld are closest, ",x,y); 37 d=0; 38 for (i=1;i<num;i++) 39 if (ans[i+1]-ans[i]>d){ 40 d=ans[i+1]-ans[i]; 41 x=ans[i];y=ans[i+1]; 42 } 43 printf("%lld,%lld are most distant. ",x,y); 44 } 45 return 0; 46 }