数论一(hdoj 简单数学题、推理题)

1008

1108

1061

题目让求N^N的最低位,N的最低位只与它最低位的N次方有关系,所以我们对一个数求它的N次方的时候,只考虑最后一位的连乘。
一个数连乘是有规律的,比如2,循环节就是2,4,8,6。数组result[]保存得就是我们的循环节。
源码如下:

#include <iostream>

using namespace std;

const int N=10;

bool used[N];

int result[N];

int main()

{

	int t,n,i;

	cin>>t;

	while(t-->0)

	{

		cin>>n;

		int dig=n%10;

		int tmp=dig;

		i=0;

		memset(used,0,sizeof(used));

		while(!used[tmp])

		{

			used[tmp]=1;

			result[i++]=tmp;

			tmp=(tmp*dig)%10;

		}

		int rs=result[(n-1)%i];

		cout<<rs<<endl;

	}

	return 0;

}

2035
求A^B的最后三位
2 3 输出8,12 6 输出984
利用性质(a*b)%m=(a%m*b)%m。

源码:

#include <iostream>

using namespace std;

int main()

{

	int a,b,ans;

	while(cin>>a>>b)

	{

		if(!a && !b)

			break;

		ans=0;

		a=a%1000;

		int tmp=a;

		while(b-->1)

		{

			a=(a*tmp)%1000;

		}

		cout<<a<<endl;

	}

	return 0;

}

1425

1021
f(1)=7,f(2)=11,f(n)=f(n-1)+f(n-2),输入一个n,判断是否能被3整除
找规律,对3取余只有3中输出0,1,2,那么f(n-2)f(n-1)就由3*3个组合情况,那么经过9个数
就会出现循环,可以列出来前几个mod3的值:
1 2 0 2 2 1 0 1 1 2 0 。。。

1005
已知f1=1,f2=1,fn=(a*fn-1+b*fn-2)%7,题目给出a,b,n求出fn
由于求对7取模,那么肯定会出现循环节(求mod运算大都会由这个规律),如果直接暴力求,肯定TLE,因为这里n为 100,000,000。
由于所有的状态组合为7*7种,所以我们只需要开一个50的数组记录状态就可以了,但是这个题出的ms有问题,所以开大点,
如果出现f[cnt-1]==1 ,f[cnt]==1,则回到了初始状态了,这时候就求出来循环节了。这里循环节长度为cnt-2,我们利用cnt%cnt得到对应下标,如果被cnt
整除,则结果为result[cnt](末尾元素).

源码:

#include <iostream>

#include <stdio.h>

using namespace std;

const int N=200;

bool used[7][7];

int result[N];

int main()

{

	int n,a,b;

	while(cin>>a>>b>>n)

	{

		if(!(a+b+n))

			break;

		memset(used,0,sizeof(used));

		used[1][1]=true;

		int cnt=3;

		result[1]=1;

		result[2]=1;

		for(cnt=3;cnt<200;++cnt)

		{

			result[cnt]=(result[cnt-1]*a+result[cnt-2]*b)%7;

			if((1 == result[cnt-1]) && (1 == result[cnt]))

				break;

		}

/*

考虑循环节不一定就是出现在1 1 ,可能为1 1 3 4 6 2 。。 3 4 。。。,所以定义一个标志数组,判断是否出现过这种组合

但是这个题始终过不了,不知道为啥	

	while(1)

		{

			f3=(f2*a+f1*b)%7;

			f1=f2;

			f2=f3;

			if(used[f1][f2])

				break;

			else

				used[f1][f2]=true;

			result[cnt]=f3;

			++cnt;

		}

*/		

		cnt-=2;

		if(n%cnt)

			cout<<result[n%cnt]<<endl;

		else

			cout<<result[cnt]<<endl;

	}

	return 0;

}

2050
平面上有n条折线,问这些折线最多能将平面分割成多少块?
我们首先考虑n条直线将平面最多分割成多少块,结论为n*(n+1)/2+1,然后我们将n条折线看成
2*n条直线,那么此时最多将平面分割成2*n(2*n+1)/2+1,由于每一条折线和2条直线相比都少分割了2个平面,所以n条折线就少分割了2*n,即最后的结论为:
2n*(2n+1)/2+1-2n

1465
n个信封,n个封皮,如果所有的信都装错了信封。求所有的信都装错信封,共有多少种不同情况。找递归公式,现在假设有n个信封,那么前N-1个信封可以要么是全部装错,要么有N-2个都装错(如果是N-3个装错,就不符合要求了,无法满足全部装错)。如果前N-1个全部装错,那么第N个信封可以和前N-1的任意一个互换,这样为n-1*f(n-1),如果有N-2个全部装错,那么我们只能把装对的那个与N交换,装对的那个可以是前n-1个的任意一个,这样情况为n-1*f(n-2),所以最后的递推公式为:
f(n)=(n-1)*(f(n-1)+f(n -2)),f1=0,f2=1 (错排公式!!!)

源码:

#include <iostream>

using namespace std;

int main()

{

	int n,cnt;

	__int64 fn_1,fn_2,fn;

	while(scanf("%d",&n)!=EOF)

	{

		fn_2=0;

		fn_1=1;

		if(1 == n)

			fn=fn_2;

		else if(2 == n)

			fn=fn_1;

		else

		{

			cnt=3;

			while(cnt<=n)

			{

				fn=(cnt-1)*(fn_1+fn_2);

				fn_2=fn_1;

				fn_1=fn;

				++cnt;

			}

		}

		printf("%I64d\n",fn);	

	}

	return 0;

}

2046

2018

有一头母牛,它每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。请编程实现在第n年的时候,共有多少头母牛?
第n年的母牛应该是原先就有的+新增的,f[n]=f[n-1]+f[n-3],f[1]=2,f[2]=2,f[3]=3,f[4]=4.

2045
有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.
我们假设已经知道前n-1个方格的图法,现在推出再加一个方格的图法,前n-1个方格可以是首位相同(我们会涂上第n个方格,这样就又满足题意了),前n-1个方格首位不同,前者我们只需要让第n个方格图另外的两种颜色中的一种,即2*f首位相同(n-1),后者的话只有一种图法,就是f首尾不同(n-1),即最后的递推公式为:f首尾不同(n)=f首尾不同(n-1)+2*f首位相同(n-1),再考虑首尾相同的递归公式,很容易得出f首尾相同(n)=f首尾不同(n-1),代码:

 

#include <iostream>

using namespace std;

int main()

{

	int n;

	__int64 fn_1e,fn_1ne,fn_e,fn_ne;

	while(scanf("%d",&n)!=EOF)

	{

		if(1 == n)

			fn_ne=3;

		else if(2 == n)

			fn_ne=6;

		else

		{

			int t=3;

			fn_1ne=6;

			fn_1e=0;

			while(t<=n)

			{

				fn_ne=fn_1ne+2*fn_1e;

				fn_e=fn_1ne;

				fn_1ne=fn_ne;

				fn_1e=fn_e;

				++t;

			}

		}

		printf("%I64d\n",fn_ne);

	}

	return 0;

}

 

hdoj2049
一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.
利用上题1465 ,这个题多了个组合,即组合+错排,result=C(n,m)*f[m],先打表

源码:

#include <iostream>

using namespace std;

__int64 f[22];

__int64 getNum(int n,int m)

{

	__int64 tmp=n,rs=1;  //一定要定义为long long

	for(int i=1;i<=m;i++)

	{

		rs*=tmp;

		--tmp;

	}

	tmp=1;

	for(int j=1;j<=m;j++)

		tmp*=j;

	return rs/tmp;

}

int main()

{

	int t,n,m;

	__int64 fn,num;

	//打表

	f[1]=0;

	f[2]=1;

	for(int i=3;i<=20;i++)

		f[i]=(i-1)*(f[i-1]+f[i-2]);

	cin>>t;

	while(t>0)

	{

		cin>>n>>m;

		num=getNum(n,m);

		fn=num*f[m];

		printf("%I64d\n",fn);

		--t;

	}

	return 0;

}

你可能感兴趣的:(数学)