从零单排1

在杭电注册了一个新的帐号,从零单排刷OJ搞起

前一段时间好多题目都是直接搜的题解,并没有真正领会要义,这个新号要保证每道题都尽量自己去做,不到万不得已不去搜题解

提纲按照这个链接来,感谢作者:http://blog.csdn.net/niushuai666/article/details/7020773


今天晚上主要做了一些简单数学题,其中

a) 欧几里德算法求最大公约数  1题,主要是上来先练手 hdu 1108
b) 筛法求素数 4题 ,分别是hdu 1164 2098 2136 2138
c) 康托展开 0题,在hdu上木有找到合适的,到一个叫hyoj的上面看了一道,自己写了一份模版
d) 逆康托展开 0题,不过也大概掌握了什么意思
e) 同余定理 1题 hdu 1136
f) 次方求模  2题 hdu 1061 2817

分析过程都写在代码注释里面了,今天主要巩固了筛法求素,学会了康托展开和快速幂求模,有一道快速幂求模也用到了同余定理的知识。

-------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------

hdu 1108:http://acm.hdu.edu.cn/showproblem.php?pid=1108

/*
最小公倍数和最大公约数
令:
int范围为4000000000大一点 
1A
*/
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a,int b)
{
	int r=a%b;
	while(r!=0)
	{
		a=b;
		b=r;
		r=a%b;
	}
	return b;
}
	
int lcm(int a,int b)
{
	return a/gcd(a,b)*b;
}
int main()
{
	int a,b;
	while(cin>>a>>b)
	{
		if(a<b)
			swap(a,b);
		cout<<lcm(a,b)<<endl;
	}
	system("pause");
	return 0;
}
hdu 1164: http://acm.hdu.edu.cn/showproblem.php?pid=1164
/*
筛法求素
1A
*/
#include<iostream>
#include<cmath>
using namespace std;
const int N=65535;
int a[N];
int prime[N];			
//筛法求素模版	
void init()
{
	int k=1;
	memset(a,1,sizeof(a));
	a[0]=0;
	a[1]=0;
	for(int i=2;i<N;i++)
	{
		if(a[i])
		{
			prime[k++]=i;
			for(int j=i+i;j<N;j+=i)
			{
				a[j]=0;
			}
		}
	}
}
void deal(int n)
{
	for(int i=1; ;i++)
	{
		if(n%prime[i]==0)
		{
			n=n/prime[i];
			cout<<prime[i];
			if(n==1)
			{
				break;
			}
			cout<<"*";
			i--;//继续判断这个素数 
			continue;
		}
	}
	cout<<endl;
}
int main()
{
	init();
	int n;
	while(cin>>n)
	{
		deal(n);
	}
	system("pause");
	return 0;
}
hdu 2098: http://acm.hdu.edu.cn/showproblem.php?pid=2098
/*
还是筛法求素
一开始先打表输出了一下
不超过10000的素数大约有1230个左右
果断hash之,注意hash范围为2N 
要注意最后应该将hash[2]置为0
这里wa了一次
*/
#include<iostream>
#include<cmath>
using namespace std;
const int N=10000;
int a[N];
int prime[N];
int hash[2*N];			
//筛法求素模版	
void init()
{
	int k=1;
	memset(a,1,sizeof(a));
	a[0]=0;
	a[1]=0;
	for(int i=2;i<N;i++)
	{
		if(a[i])
		{
			prime[k++]=i;
			for(int j=i+i;j<N;j+=i)
			{
				a[j]=0;
			}
		}
	}
}
void f()
{
	for(int i=1;i<1240;i++)
	{
		for(int j=i+1;j<=1240;j++)
		{
			hash[prime[i]+prime[j]]++;
		}
	}
	hash[2]=0;//注意hash[2]=0 
}
			
		
int main()
{
	int n;
	init();
	f();
	while(cin>>n&&n)
	{
		cout<<hash[n]<<endl;
	}
	system("pause");
	return 0;
}
hdu 2136: http://acm.hdu.edu.cn/showproblem.php?pid=2136
/*
筛法求素应用
开始用cin,cout结果TLE了
一开始不知道是这里的错误开大了数组结果MLE了
最后改用scanf和print后过了
*/
#include<iostream>
#include<cmath>
using namespace std;
const int N=1000000;
int a[N];//素数表 
int lpf[N];			
//筛法求素模版	
void init()
{
	int k=0;
	memset(a,1,sizeof(a));
	a[0]=0;
	a[1]=0;
	lpf[1]=0;
	for(int i=2;i<N;i++)
	{
		if(a[i])
		{
			k++;
			lpf[i]=k;
			for(int j=i+i;j<N;j+=i)
			{
				a[j]=0;
				lpf[j]=k;
			}
		}
	}
}
int main()
{
	int n;
	init();
	while(scanf("%d",&n)!=EOF)
	{
		printf("%d\n",lpf[n]); 
	}
	system("pause");
	return 0;
}
		
hdu 2138: http://acm.hdu.edu.cn/showproblem.php?pid=2138
/*
本来想套素数表的。。
结果果断RE
后来该普通方法
C++因为sqrt的重载问题过不了
G++过了
*/
#include<iostream>
#include<cmath>
using namespace std;
bool isprime(int n)
{
	if(n==1)
		return false;
	for(int i=2;i<=sqrt(n);i++)
	{
		if(n%i==0)
			return false;
	}
	return true;
}
int main()
{
	int n;
	while(cin>>n)
	{
		int a;
		int sum=0;
		while(n--)
		{
			cin>>a;
			if(isprime(a))
			{
				sum++;
			}
		}
		cout<<sum<<endl;
	}
	system("pause");
	return 0;
} 
//自己写的模版
/*
康托展开
木有找到练习题。。
先一个模版再说
把一个整数X展开成如下形式:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[2]*1!+a[1]*0!
其中,a为整数,并且0<=a[i]<i(1<=i<=n)
{1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个。
123 132 213 231 312 321 。
代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来。
他们间的对应关系可由康托展开来找到。
如我想知道321是{1,2,3}中第几个大的数可以这样考虑 :
第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。
所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 
所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。 
2*2!+1*1!+0*0!就是康托展开。
再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,
是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。
第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,
所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。
*/
#include<iostream>
#include<cstring>
using namespace std;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
int cantor(char s[],int n)
{
	int temp,num;
	num=0;
	for(int i=0;i<n-1;i++)
	{
		temp=0;
		for(int j=i+1;j<n;j++)//n为位数 
		{
			if(s[j]<s[i])
			{
				temp++;
			}
		}
		num+=fac[n-(i+1)]*temp;
	}
	return num+1;
} 
int main()
{
	char s[10];
	while(cin>>s)
	{
		cout<<cantor(s,strlen(s))<<endl;
	}
	system("pause");
	return 0;
}

hdu 1163:http://acm.hdu.edu.cn/showproblem.php?pid=1163

/*
同余定理
这题木有什么思路,搜到了题解
因为ab*ab=(10*a+b)*(10*a+b)=100*a*a+10*2*a*b+b*b=a*a+2*a*b+b*b=(a+b)*(a+b)
abc*abc=(100*a+10*b+c)*(100*a+10*b+c)
               =10000*a*a+2000*a*b+100*b*b+200*a*c+20*b*c+c*c
               =a*a+2*a*b+b*b+2*a*c+2*b*c+c*c
               =(a+b)^2+2*c*(a+b)+c*c
              = (a+b+c)*(a+b+c)
同理可以知道四位数,五位数也一样,
即n*n的数根=n的数根*n的数根
数论当中有个结论:“某数乘积的九余数=等于该数九余数的乘积”当余数为0时,该数为九。
*/
#include <iostream>
using namespace std;
int main()
{
	int n;	
	while(cin>>n&&n)
	{
		int i;
		int s=1;
		for(i=0;i<n;++i)
		{
			s=(s*n)%9;
		}
		if(s==0)
			cout<<"9"<<endl;
		else
			cout<<s<<endl;
	}
	return 0;
} 

hdu 1061: http://acm.hdu.edu.cn/showproblem.php?pid=1061

/*
快速幂
没有使用long long 导致wa了两次
*/
#include<iostream>
using namespace std;
//快速幂模版 
int ModExp(long long a,long long b,long n)
{
	long long result=1;
	long long y=a;
	while(b)
	{
		if(b%2)
		{
			result=result*y%n;
		}
		y=y*y%n;
		b/=2;
	}
	return result;
}
int main()
{
	int T;
	long long num;
	cin>>T;
	while(T--)
	{
		cin>>num;
		cout<<ModExp(num,num,10)<<endl;
	}
	system("pause");
	return 0;
}
hdu 2817: http://acm.hdu.edu.cn/showproblem.php?pid=2817
/*
好奇葩的题
快速幂
然后是学会了用__int64
另外long long 导致wa了好多次 
*/
#include<iostream>
#include<cstdio>
#define N 200907
using namespace std;
//快速幂模版 
__int64 ModExp(__int64 a,__int64 b,__int64 n)
{
	__int64 result=1;
	__int64 y=a;
	while(b)
	{
		if(b%2)
		{
			result=result*y%n;
		}
		y=y*y%n;
		b/=2;
	}
	return result;
}
int main()
{
    __int64 a,b,c,d,k,q;
    scanf("%I64d",&a);
    while(a--)
    {
        scanf("%I64d%I64d%I64d%I64d",&b,&c,&d,&k);
        if(2*c==b+d)
        {
            b=b%N+(k-1)%N*((c-b)%N);
            b=b%N;
            printf("%I64d\n",b);
        }
        else if(c*c==b*d)
        {
            if(k>1)
            {
                q=(d/c)%N;
                b=(b%N)*ModExp(q,k-1,N);
                b=b%N;
                printf("%I64d\n",b);
            }
            else
            printf("%I64d\n",b);
        }
    }
    return 0;
}

明天要把大一上的知识点过完,加油~!

PS:感觉这样很有效果貌似~!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值