数论总结

数论 (由用使用markdown写的代码无法缩进篇幅较长...)

A - 质数筛 LightOJ - 1370

思路 : 运用了欧拉函数的一个性质 :当n为质数是 f(n)=n-1
问题 给出 一个分数要求 竹子长度的欧拉函数大于等于分数
由上述定理可知长度一定大于分数 只需要找到分数+1往上的一个素数
减去1就是满足要求的最最短长度的最大的分数 !
代码如下

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int prime[1000025],pri[1000025],ans=0;
int main()
{
    int n,t;
    memset(prime,1,sizeof(prime));
    prime[0]=prime[1]=0;
    for(int i=2;i<=1000020;i++)
    {
        if(prime[i])
           pri[ans++]=i;
           for(int j=0;j<ans&&i*pri[j]<=1000020;j++)
           {
             prime[i*pri[j]]=0;
             if(!i%pri[j])
               break;           
           }
    } 
    cin>>t;
for(int k=1;k<=t;k++)
{    
    cin>>n;
    long long sum=0;
    for(int i=0;i<n;i++)
    {
        int a;
        cin>>a;
        for(int j=a+1;;j++)
        {
            if(prime[j])
            {
                sum+=j;
                break;
             }
         }
     }
     printf("Case %d: %lld Xukha\n",k,sum);
}
    return 0;
}



B - 分解质因数 LightOJ - 1341

思路: 欧拉筛素数 唯一分解定理 暴力 根下10^12=10^6
唯一分解定理 p=p1^a1p2^a2....pn^an;
则 P的因子个数为 sum=(1+a2)(1+a2)(1+an);
代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 1000010
using namespace std;
bool flag[maxn];
int pri[maxn],sum,t,ans=0;
long long a,b;
int main()
{

    memset(flag,1,sizeof(flag));
    for(int i=2;i<=maxn;i++)
    {
        if(flag[i])
         pri[ans++]=i;
         for(int j=0;j<ans&&pri[j]*i<=maxn;j++)
         {
            flag[pri[j]*i]=0;
            if(!i%pri[j])
             break;
         }
    }
    cin>>t;
    for(int tt=1;tt<=t;tt++)
    {
        cin>>a>>b;
         if(a<b*b)
           printf("Case %d: 0\n",tt);
        else
        {
            int cnt=0;
            sum=1;
            for(int i=1;i<b;i++)
            if(!(a%i))
            cnt++;
            for(int i=0;i<ans&&pri[i]<=sqrt(a);i++)
            {
                int ant=0;
                while(!(a%pri[i]))
                {
                    ant++;
                    a/=pri[i];
                }
                sum*=ant+1;
            }
            if(a>1)
            sum*=2;
            sum/=2;
          printf("Case %d: %d\n",tt,sum-cnt);
        }
    }
    return 0;
 } 



D - Leading and Trailing LightOJ - 1282

思路:大数转化 快速幂 模拟快速幂
正常 为 取余所mod数
前置保留利用 double型数据 进行前几位保操作
当 乘积大于等于1000 数字/10;最终转换为int输出就是
前三位 PS:后三位存在前导零
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
    int t;
    LL num;
    int k,l;
    double f;
    cin>>t;
  for(int  tt=1;tt<=t;tt++)
  {
    cin>>num>>k;
     LL numm=num;
     l=1;
     int m=k;
     while(k)
     {
        if(k%2)
        {
            l%=1000;
            l*=numm%1000;   
        }
        numm%=1000;
        numm*=numm; 
        k/=2;
    }
    l%=1000;
    double nummm=num*1.0;
    f=1.0;
    while(m)
    {
        if(m%2)
        {
         while(f>=1000.0)
            f/=10.0;
        f*=nummm;
        }
        while(nummm>=1000.0)
            nummm/=10.0;    
        nummm*=nummm;
        m/=2;
    }
    while(f>=1000.0)
      f/=10.0;
    int ff=f;
  printf("Case %d: %d %03d\n",tt,ff,l);
  }
}



E - Goldbach`s Conjecture LightOJ - 1259

思路:欧拉筛素数+暴力
利用欧拉筛特性 生成的标记数组 以及 素数数组进行
素数 与 数字减去素数 判定 效率提升
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=1e7+10;
int pri[5000000];
bool map[maxn];
int main()
{
    
    memset(map,1,sizeof(map));
    int ans=0;
    map[1]=0;
    for(int i=2;i<maxn;i++)
    {
        if(map[i])
        pri[ans++]=i;
        for(int j=0;j<ans&&pri[j]*i<maxn;j++)
        {
            
         map[i*pri[j]]=0;
         if(!(i%pri[j]))
         break;
        }
    }
    int n;
    cin>>n;
    for(int time=1;time<=n;time++)
    {
        int num,cnt=0;
        cin>>num; 
        for(int i=0;i<ans&&pri[i]<=num/2;i++)
        {
           if(map[num-pri[i]]) 
              cnt++;
        }
        printf("Case %d: %d\n",time,cnt);
    }
    return 0; 
} 



F - Harmonic Number (II) LightOJ - 1245

思路: 验证得出 数字sqrt(n)之前可以直接计算
sqrt(n)之后可以通过 区间计算缩短运算时间 进而防止TLE出现
诸如 3=n/3---n/4之间的数据
区间和为 3*(n/4-n/3)
代码如下:

#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
int main()
{
    int T;
    LL n;
    cin>>T;
    for(int cas=1; cas<=T; cas++)
    {
        cin>>n;
        int m = sqrt(n);
        LL ret = 0;
        for(int i=1; i<=m; i++)
            ret += n/i;
        for(int i=1; i<=m; i++)
            ret += (n/i - n/(i+1))*i;
        if(m == n/m)
            ret -= m;
        cout<<"Case "<<cas<<": "<<ret<<endl;
    }
    return 0;
}



H - Harmonic Number LightOJ - 1234

思路:有2.
1 ). 10000之前进行直接计算,10000之后利用欧拉常数直接求值
2 ).10^8数据每40个数据存一次实际 运算 sum一直在++但始终没有明白
所谓的1000ms究竟限制的是哪一部分 10^8的运算 但却没有超3S限制
(这个思路很新奇 )
欧拉常数:r=0.57721566490153286060651209;
a=log(n)+r+1.0/(2*n);
代码1:

 #include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const double r=0.57721566490153286060651209;
double a[10008];
int main()
{
    a[1]=1;
    for(int i=2;i<10007;i++)
    {
        a[i]=a[i-1]+1.0/i;
    }
    int t;
    cin>>t;
    for(int tt=1;tt<=t;tt++)
{
    long long n;
    cin>>n;
    if(n<10000)
    printf("Case %d: %.10lf\n",tt,a[n]);
    else
    printf("Case %d: %.10lf\n",tt,log(n)+r+(1.0/(2.0*n))); 
}
        return 0;
 } 

代码二:

#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 1e8+10
#define mine 2500005
using namespace std;
double  num[mine];
int main()
{
    int t;
    long long  n;
    double sum=1;
    num[1]=1;
    for(long long  i=2;i<=maxn;i++)
    {
        sum+=(1.0/i);
        if(!(i%40))
        num[i/40]=sum;
    }
    cin>>t;
    for(int time=1;time<=t;time++)
    {
        cin>>n;
        long long x=n/40;
        sum=num[x];
        for(long long ll=n;ll>40*x;ll--)
        sum+=(1.0/ll);
        printf("Case %d: %.10lf\n",time,sum);
    }
    
    return 0;
 } 



I - Mysterious Bacteria LightOJ - 1220

思路: 唯一分解定理 + gcd()
利用唯一分解定理将数字分解成 若干 数字幂相乘形式
利用gcd 求出他们最大公约数 来判断最小幂数
(例子:2^23^4-gcd(2,4)=2--(23^2)^2=18^2
2^23^3-gcd(2,3)=1--427^1)
另外要注意 负数形式
只有当 幂次为奇数是才为负数 因此要将求得gcd不断判断偶则/2
直至为奇数 才为最终答案 !~
代码如下:

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int maxn = 1e5+10;
bool vis[maxn] = {0};
int prime[maxn];
int ret;
void IsPrime()
{
    ret = 0;
    vis[1] = 1;
    for(int i = 2 ; i <= maxn ; i++)
    {
        if(vis[i] == 0)
        {
            prime[ret++] = i;
            for(int j = 2 ; j * i < maxn ; j++)
            {
                vis[i*j] = 1;
            }
        }
    }
}
signed main()
{
    int t , ans;
    ll n;
    IsPrime();
    cin >> t;
    for(int k = 1 ; k <= t ; k++)
    {
        cin >> n;
        int sum = 0 ;
        int flag = 0;
        if(n < 0)
        {
            n = -n;
            flag = 1;
        }
        for(int i = 0 ; i < ret ; i++)
        {
            if(n % prime[i] == 0)
            {
                ans = 0;
                while(n % prime[i] == 0)
                {
                    ans++;
                    n /= prime[i];
                }
                if(sum == 0)
                {
                    sum = ans;
                }
                else
                {
                    sum = __gcd(sum , ans);
                }   
            }
        }
        if(n > 1)
        {
            sum = 1;
        }
        if(flag == 1)
        {
            while(sum % 2 == 0)
            {
                sum = sum/2;
            }
        }
        printf("Case %lld: %lld\n" , k , sum);
    }
    return 0;
 } 



J - Large Division LightOJ - 1214

思路:大数模拟 暴力? 取余定理 a=c+d-a%b=(c%b+d%b)%b;
核心 大数模拟 numnow=numago*10+(string)b[now]-48; numnow%=b;
代码如下:

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<sstream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    for(int t=1;t<=n;t++)
    {
        string a;
        char as[1000];
        long long b,x=0;
        cin>>a>>b;
        if(a.length()==1&&a[0]=='0')
     printf("Case %d: divisible\n",t);
else
{
       abs(b);
        if(a[0]=='-')
        a.erase(0,1);
        for(int i=0;i<a.length();i++)
        {
            x=(x*10+a[i]-'0')%b;
        }
        x%=b;
        if(!x)
     printf("Case %d: divisible\n",t);
      else
     printf("Case %d: not divisible\n",t);
    }
    
        }    
    return 0; 
} 



M - Trailing Zeroes (III) LightOJ - 1138

思路: 推理得知 0的个数只与 数字/5之和 相互映射
例子 5! ---120 5/5=1;
10!---10/5=2+2/5=2;
避免超时采用二分思路
代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
typedef long long  LL;
LL sum(LL n )
{
    LL ans=0;
    while(n)
    {
        ans+=n/5;
        n/=5;
    }
    return ans;
}
int main()
{
int t;
cin>>t;
int cnt=1;
while(t--)
{
      LL mid,q,left=1,right=1000000000,ans=0;
      cin>>q;
      while(right>=left)
      {
        mid=(left+right)/2; 
        if(sum(mid)<q)
          left=mid+1;
        else
          right=mid-1; 
      }
      int x=sum(left);
      if(x==q)
          printf("Case %d: %d\n",cnt++,left);
      else
           printf("Case %d: impossible\n",cnt++);
}
    return 0;
} 



T - Primes HDU - 2161

思路:这题真水 就是题干 定义2不是素数
直接 欧拉筛1e6数据水过
代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e6+10;
typedef long long  LL;
int pri[maxn];
bool p[maxn];
int main()
{
    int ans=0;
    memset(p,1,sizeof(p));
    for(int i=2;i<=maxn;i++)
    {
       if(p[i])
        pri[ans++]=i;
        for(int j=0;j<ans&&pri[j]*i<=maxn;j++)
        {
            p[pri[j]*i]=0;
            if(!(i%pri[j]))
               break;
        }     
    }
    p[1]=p[2]=0;
    int a,i=1;
while(cin>>a)
{
    if(a<=0)
    break;
printf("%d: ",i++);
if(p[a])
cout<<"yes";
else
cout<<"no";
cout<<endl;
}
    return 0;
 } 



U - Maximum GCD UVA - 11827

思路 : 字符流转换 以及getlin() gcd()
下stringstream ;
stringstream与 getline()详解
代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>   
#include<cmath>
#include<sstream>
#include<algorithm>
using namespace std;
long long gcd(long long a,long long b)
{
    if(b==0)
    return a;
    else
    return gcd(b,a%b);
}
int main()
{    
long long  a[105],t;
cin>>t;
getchar();
while(t--)
{
    long long   ans=0,maxn=-1;
string str;
getline(cin,str);
stringstream st(str);
while(st>>a[ans])
{
ans++;  
}

        for(int i=0;i<ans;i++)
        {
            for(int j=i+1;j<ans;j++)
            {
                long long  c=a[i],d=a[j];
            while(d^=c^=d^=c%=d);
             maxn=max(maxn,c);      
            }
        }
        cout<<maxn<<endl;
}
    return 0;
}           

转载于:https://www.cnblogs.com/maxv/p/10992810.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值