A - 一只小蜜蜂...
有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。
其中,蜂房的结构如下所示。
2 1 2 3 6
1 3
解题思路:从图中可以看出,由1→3,可能的情况有两种:1→3或2→3。
即:若要到达X(X>=3),则上一步的状态为X-1或X-2。
由此得出递推公式:f[x]=f[x-1]+f[x-2].(x>=3)
代码:
#include<stdio.h>
long long c[60]={1,1};
void dg(int x)
{
for(int i=2;i<x;i++)
c[i]=c[i-1]+c[i-2];//递推
}//预处理
int main()
{
int n;
dg(50);
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",c[b-a]);//解只取决于起点和终点之间的距离
}
return 0;
}
B - 不容易系列之(3)―― LELE的RPG难题
有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.
以上就是著名的RPG难题.
如果你是Cole,我想你一定会想尽办法帮助LELE解决这个问题的;如果不是,看在众多漂亮的痛不欲生的Cole女的面子上,你也不会袖手旁观吧?
1 2
3
6
解题思路:题目要求有两个:相邻颜色不同,首尾颜色不同,设由长度为N的色块涂法为f[n]
开始递推,假设有长度为N(N>=4)的色块要涂,设首位为R,空出最后两个色块考虑
R........_ _
最后一个色块的涂法有两种情况。如果倒数第二块色块为R,则最后一块可以涂P或G,此时倒数第3块色块不可能是R,前N-2块色块的涂法满足f[n-2];如果倒数第二块色块不为R,则最后一块只能涂P或G其中1个,前N-1块涂法满足f[n-1]。
得出递推公式:f[n]=2*f[n-2]+f[n-1](n>=4)
代码:
#include<stdio.h>
long long c[60]={3,6,6};
int dg(int x)
{
for(int i=3;i<x;i++)
c[i]=c[i-1]+c[i-2]*2;//递推
return 0;
}
int main()
{
int n;
dg(50);//预处理
while(scanf("%d",&n)!=EOF)
{
printf("%lld\n",c[n-1]);
}
return 0;
}
C - 骨牌铺方格
在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数.
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:
1 3 2
1 3 2
解题思路:设要铺设的长方形长度为n(n>=2),方法种数为f[n];
假设我们现在已经几乎铺完这个长方形,还有一步,就可以把长方形铺满,最后一步的情况有两种:
剩余2的长度,铺法:
前面长度的铺法为f[n-2]
剩余1的长度,铺法:
前面长度的铺法为f[n-1]
那么总共的铺法种数f[n]为这两种铺法种数只和,得到递推公式f[n]=f[n-2]+f[n-1].
代码:
#include<stdio.h>
long long c[60]={1,2,3};
int dg(int x)
{
for(int i=3;i<x;i++)
c[i]=c[i-1]+c[i-2];
return 0;
}
int main()
{
int n;
dg(50);
while(scanf("%d",&n)!=EOF)
{
printf("%lld\n",c[n-1]);
}
return 0;
}
D - 阿牛的EOF牛肉串
今年的ACM暑期集训队一共有18人,分为6支队伍。其中有一个叫做EOF的队伍,由04级的阿牛、XC以及05级的COY组成。在共同的集训生活中,大家建立了深厚的友谊,阿牛准备做点什么来纪念这段激情燃烧的岁月,想了一想,阿牛从家里拿来了一块上等的牛肉干,准备在上面刻下一个长度为n的只由"E" "O" "F"三种字符组成的字符串(可以只有其中一种或两种字符,但绝对不能有其他字符),阿牛同时禁止在串中出现O相邻的情况,他认为,"OO"看起来就像发怒的眼睛,效果不好。
你,NEW ACMer,EOF的崇拜者,能帮阿牛算一下一共有多少种满足要求的不同的字符串吗?
PS: 阿牛还有一个小秘密,就是准备把这个刻有 EOF的牛肉干,作为神秘礼物献给杭电五十周年校庆,可以想象,当校长接过这块牛肉干的时候该有多高兴!这里,请允许我代表杭电的ACMer向阿牛表示感谢!
再次感谢!
1 2
3
8
解题思路:设长度为n的刻法有f[n]中,第n个字母是o的种数为o[n],第n个字母不是n的种数为x[n].
从n=1开始递推:
x[1]=2;
o[1]=1;
f[n]=o[n]+x[n];
n=2:不论第一个字母是什么,第二个字母都可以刻E或F,所以x[2]=2*f[1].当前一个字母不是o时,第二个字母才能刻o,则o[2]=x[1].
由此得到递推规律:x[n]=2*f[n-1];
o[n]=x[n-1];
f[n]=o[n]+x[n];
代码:
#include<stdio.h>
long long c[60][2];//我用二维数组来储存x[n]和o[n]
int dg(int x)
{
c[0][0]=2;
c[0][1]=1;
for(int i=1;i<x;i++)
{
c[i][0]=2*(c[i-1][0]+c[i-1][1]);
c[i][1]=c[i-1][0];
}
return 0;
}
int main()
{
int n;
dg(50);
while(scanf("%d",&n)!=EOF)
{
printf("%lld\n",c[n-1][0]+c[n-1][1]);
}
return 0;
}
E - 神、上帝以及老天爷
HDU 2006'10 ACM contest的颁奖晚会隆重开始了!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:
首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”
大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!
我的神、上帝以及老天爷呀,怎么会这样呢?
不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?
不会算?难道你也想以悲剧结尾?!
1 2
50.00%
递推过程:用A-1,B-2来代表是否抽到自己的名字,例:
A B C D E
1 2 3 4 5
此时n=5,考虑E,E没有拿到自己的名字,种数为n-1,此时(例举一种情况):
A B C D E
1 2 3 5 4
若D拿到5, 则剩下的3个人拿错的种类为f[3];
若D不拿5,可以看做D拿到5是中奖的,剩下的4人排列类似于:
A B C D
1 2 3 4
拿错种数为f[4];
得到f[5]=(5-1)*(f[4]+f[3]);
递推公式f[n]=(n-1)*(f[n-1]+f[n-2]);
全部的排列为s[n]=n!;
概率为f[n]/s[n];
代码:
#include<stdio.h>
double s[30]={0,1,2},n[30]={0,0,1};
void gl(int x)
{
for(int i=3;i<x;i++)
{
n[i]=(i-1)*(n[i-1]+n[i-2]);
s[i]=s[i-1]*i;
}
}
int main()
{
int i,c;
char x='%';
gl(25);
scanf("%d",&c);
while(c--)
{
scanf("%d",&i);
printf("%.2f%c\n",(n[i]/s[i])*100,x);
}
return 0;
}
F - 不容易系列之(4)――考新郎
国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的:
首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个.
最后,揭开盖头,如果找错了对象就要当众跪搓衣板...
看来做新郎也不是容易的事情...
假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.
2 2 2 3 2
1 3
解题思路:错排递推如E,错排的种数乘上排列即可;
代码:
#include<stdio.h>
long long s[30]={1,1,2},w[30]={0,0,1};
void gl(int x)
{
for(int i=3;i<x;i++)
{
w[i]=(i-1)*(w[i-1]+w[i-2]);
s[i]=s[i-1]*i;
}
}
int main()
{
int n,m,c;
gl(21);
scanf("%d",&c);
while(c--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",w[m]*(s[n]/(s[m]*s[n-m])));
}
return 0;
}
G - 折线分割平面
我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目。比如,一条折线可以将平面分成两部分,两条折线最多可以将平面分成7部分,具体如下所示。
2 1 2
2 7
解题思路:先从直线分割平面开始递推。易得当画第i条线时,最多可与前面画的嫌产i-1个交点,产生(i-1)+1个面;
同理,当话第i条折线时,最多可以产生2*2*(i-1)个点,产生4*(i-1)+1个新面;
得到递推公式:f[i]=f[i-1]+4*(i-1)+1;
代码:
#include<stdio.h>
long long s[11000]={1,2,7};
void gl(int x)
{
for(int i=3;i<x;i++)
{
s[i]=s[i-1]+4*(i-1)+1;
}
}
int main()
{
int n,c;
gl(10050);
scanf("%d",&c);
while(c--)
{
scanf("%d",&n);
printf("%lld\n",s[n]);
}
return 0;
}
H - 超级楼梯
2 2 3
1 2
递推过程:跨上第M介台阶的那一步有两种情况从M-2→M,从M-1→M。分别对应f[m-2]和f[m-1];
得到递推公式f[n]=f[n-1]+f[n-2];
代码:
#include<stdio.h>
int main()
{
long long f[45]={0,0,1,2};
int c,n;
for(int i=4;i<45;i++)
f[i]=f[i-1]+f[i-2];
scanf("%d",&c);
while(c--)
{
scanf("%d",&n);
printf("%lld\n",f[n]);
}
return 0;
}