1. 题目
2.Valentine’s Coat(coat)
描述
今天是情人节,小杉在参加一个valentine’s party!
Oh,it sounds good.
现在已经是晚上10点了,参加party的n个人很无聊,于是开始玩一个游戏。
每个人先穿一件白外套,再站成一个圈,然后给每件外套上色。总共有k种颜色可以上。
一个可爱的上色方案应该满足对于每一个人,他身边的两个人所穿的外套颜色都和他所穿的不同。
小杉现在想知道总共有多少种可爱的上色方案。
输入格式
一行两个整数n,k(1<=n<=3000,1<=k<=10)
输出格式
仅有一行,一个整数,为上色方案数对19900801取模的结果
样例输入
2 2
样例输出
2
样例解释
譬如小杉和小小杉玩这个游戏,给小杉上第一种颜色,给小小杉上第二种颜色,或者相反,都是可爱的上色方案,总共两种。
2. 题目实质
这个模型很简单,就是给一个环形元素集合上色,相邻元素不能颜色相同。求上色方案数。
3. 算法
仍旧是递推。
首先,显然,当 n=1 时, k 即为所求。
由于每个人是不同的,我们这样考虑,把环拉成一条线,令f[i]为i个数,首尾颜色不同的方案数。f[i]可以由首尾相同的i-1个数再加上一个不同于首尾的数得到,或者由首尾不同的i-1数再加上一个不同于首尾的数得到,前者为f[i-2]*(k-1)(首尾相同的i-1个数和首尾不同的i-2个数是等价的),后者为f[i-1]*(k-2)。初始为f[1]=0,f[2]=k*(k-1)
于是我们得到f[i]=f[i-1]*(k-2)+f[i-2]*(k-1),即(f[i]+f[i-1])=(f[i-1]+f[i-2])*(k-1),而f[1]+f[2]=k*(k-1),于是f[i]+f[i+1]=k*(k-1)^i,即f[i+1]=-f[i]+k*(k-1)^i,即(-1)^(i+1)f[i+1]=(-1)^if[i]-k*(1-k)^i,换元后使用等比数列求和公式可得f[i]=(k-1)^i+(-1)^i*(k-1)。注意若n=1,应输出k而不是0。
当然,使用f[i]=f[i-1]*(k-2)+f[i-2]*(k-1)递推也是可以的。
4. 注意事项
这个题不要用快速幂,第一, NOIP 不怎么考,第二,会报栈溢出的,就像 std 一样。
5. 程序代码
绝恋LOVE枫 (pascal)
program coat(input,output);
var
ans : int64;
n,k : longint;
function power(x,y: longint ):int64;
var
i : longint;
begin
power:=1;
for i:=1 to y do
power:=(power*x) mod 19900801;
end; { power }
begin
assign(input,'coat.in');reset(input);
assign(output,'coat.out');rewrite(output);
readln(n,k);
ans:=0;
if (n=1)and(k=1) then
ans:=1
else
if (n mod 2=1) then
ans:=power(k-1,n)-(k-1)
else
ans:=power(k-1,n)+(k-1);
writeln(ans);
close(input);
close(output);
end.