1008
1108
1061
题目让求N^N的最低位,N的最低位只与它最低位的N次方有关系,所以我们对一个数求它的N次方的时候,只考虑最后一位的连乘。
一个数连乘是有规律的,比如2,循环节就是2,4,8,6。数组result[]保存得就是我们的循环节。
源码如下:
#include
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<
2035
求A^B的最后三位
2 3 输出8,12 6 输出984
利用性质(a*b)%m=(a%m*b)%m。
源码:
#include
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<
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
#include
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<
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
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
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
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
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;
}