poj3421&poj3292&poj2689 基础数论

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\n",len,ans);
39     }
40     return 0;
41 }
poj3421

 

 

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 }
poj3292

 

 

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.\n");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.\n",x,y);
44     }
45     return 0;
46 }
poj2689

 

posted @ 2020-04-21 22:24  coastal_taipan  阅读(171)  评论(0)    收藏  举报