zoukankan      html  css  js  c++  java
  • 数论总结

    数论 (由用使用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
    ",k,sum);
    }
    	return 0;
    }
    



    B - 分解质因数 LightOJ - 1341

    思路: 欧拉筛素数 唯一分解定理 暴力 根下1012=106
    唯一分解定理 p=p1a1*p2a2....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
    ",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
    ",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
    ",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
    ",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
    ",tt,a[n]);
    	else
    	printf("Case %d: %.10lf
    ",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
    ",time,sum);
    	}
    	
    	return 0;
     } 
    



    I - Mysterious Bacteria LightOJ - 1220

    思路: 唯一分解定理 + gcd()
    利用唯一分解定理将数字分解成 若干 数字幂相乘形式
    利用gcd 求出他们最大公约数 来判断最小幂数
    (例子:22*34-gcd(2,4)=2--(232)2=18^2
    22*33-gcd(2,3)=1--4
    27^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
    " , 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
    ",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
    ",t);
    	  else
         printf("Case %d: not divisible
    ",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
    ",cnt++,left);
    	  else
    	       printf("Case %d: impossible
    ",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;
    }           
    
    
  • 相关阅读:
    php 下载保存文件保存到本地的两种实现方法
    MySQL select语句直接导出数据
    Go学习笔记03-附录
    Go学习笔记02-源码
    Go学习笔记01-语言
    Go语言极速入门手册
    最简单的抓取网络图片或音乐文件
    使用PHP生成PDF文档
    Oracle常用函数
    ORACLE常用数值函数、转换函数、字符串函数
  • 原文地址:https://www.cnblogs.com/maxv/p/10992810.html
Copyright © 2011-2022 走看看