zoukankan      html  css  js  c++  java
  • 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
    ",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.
    ");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 }
    poj2689
  • 相关阅读:
    标准Gitlab命令行操作指导
    ssh登录巨慢加速验证
    ssh远程主机执行命令或脚本
    ssh创建与添加密钥开启免密登陆 免确认机器指纹参数
    linux免密传输文件 nc
    Linux 查看实时网卡流量的方法 网速 nload sar iftop dstat
    Mysql 常用命令
    Redis 常用命令整理
    shell sed -i 指定内容追加.
    java 复制指定目录中的所有文件和文件夹到另一个指定文件夹中
  • 原文地址:https://www.cnblogs.com/edmunds/p/12748416.html
Copyright © 2011-2022 走看看