zoukankan      html  css  js  c++  java
  • 数论一(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;
    }
    
  • 相关阅读:
    【ES】学习10-聚合3
    Flink – CEP NFA
    cruise-control
    FlinkCEP
    Flink
    SQL Join
    Flink – Stream Task执行过程
    Flink
    Java8
    Flink
  • 原文地址:https://www.cnblogs.com/buptLizer/p/2221939.html
Copyright © 2011-2022 走看看