Problem Description
I think that you might have played the traditional Chinese ring game: The Chinese Linking Rings (here we call its nickname Jiulianhuan —— “九连环”). Well, you say you haven’t played it before? Then you must have seen it before, right? If not seen, come to borrow mine to have a good look at it and enjoy it!
Now, I would like to mention the rules or common sense of Jiulianhuan again.
1)The first ring can put on or down the handles at any time. That is, when the first ring is under the handle, it can climb up the handle within one step, and vice versa.
2)At any moment, you can only operate one ring, on the condition that the ring is operable.
3)If the first k-2 rings are under the handle, and the (k-1)th ring is on the handle, then if the k-th ring is under the handle, you can put it on the handle, and if it is not under the handle, you can put it down the handle.
Seems complicated? But I tried my simplest explanation to you, and I hope its not hard for you to understand. Maybe you have played the game before, and the above is what actually a “step” means in the game.
Input
Given n (not bigger than 108), you are to output the minimum steps it needs to down n well-put rings. There are no more than 100 test cases.
Output
A number a line. Because the number are so huge ,you are to output the result after it mod prime 10007.
Sample Input
1 2 9 1005
Sample Output
1 2 341 0 我承认自己的英语渣!然后现在标程解:
解题思路:
第一环可以随时取下或者套上
一次只能取下或者套上一环
设要取下的是第k环,那么前k-2环必然在杆下,第k-1环必然在杆上,只有这样第k环才能取下,并且取下之后,第k-1环还在杆上,前k-2环在杆下(套上的规则也是类似)
玩1连环,直接取下,ok;
玩2连环,先下第二环(根据3),然后就相当于解1连环了;
玩3连环,先下第一环,之后第三环可以摘下(也是根据3),这个时候只有第二环孤零零地在杆上,之后我们把第一环套上,问题转化为2连环了;
。。。。。。。。。。。
玩k连环,那么第k环是要解下的,而要解下第k环,我们就要先解下前k-2环,这样在杆上的第k环可以依靠在杆上的第k-1环解下(规则3)。第k环解下之后,杆上只有第k-1环,前k-2环在杆下。如果前k-2环不上去,第k-1环就无法解下。所以我们要上前k-2环(稍微一想就知道,上i个环和下i个环的最少步骤必然是相等的,因为是逆过程)好了,上了前k-2环之后,此时杆上就排好了k-1环接下来怎么办?对,递归!
设f[n]是下n连环的最少步骤。那么,要先下前n-2,然后再下第n,然后安装前n-2,然后下前n-1
所以,f[n]=f[n-2]+1+f[n-2]+f[n-1]
=f[n-1]+2*f[n-2]+1
F[0]=0,f[1]=1
可以矩阵乘法了,如果不嫌麻烦
生成函数。
设G(x)=f[0]+f[1]*x+f[2]*x^2+f[3]*x^3+f[4]*x^4+……+f[n]*x^n+….
那么x*g(x)= f[0]*x+f[1]*x^2+f[2]*x^3+f[3]*x^4+….+f[n-1]*x^n+…
并且2*x^2*g(x)= 2*f[0]*x^2+2*f[1]*x^3+2*f[2]*x^4+.+2*f[n-1]*x^n
第一式减下两式,并且根据递推关系,得
(1-x-2*x^2)G(x)=f[0]+f[1]*x-f[0]*x+x^2+x^3+x^4+….+x^n+…
=x+x^2+x^3+…+x^n+…=x/(1-x) (生成函数x没有实际意义
,所以认为无穷级数收敛)
所以G(x)=(x/(1-x))/(1-x-2*x*x)=x/((1-x)*(1+x)*(1-2*x))
将其展开为c/(ax+b)的形式,得到
G(x)= - ( 1/(1-x)*3/2+1/(1+x)*1/2 )/3+ 1/(1-2*x)*2/3
根据1/(1-x)=1+x+x^2+….+x^n+…
得到f[n]= (2^(n+2)-3-(-1)^n)/6
推导有点耗时呢,用其它方法可以么?
注意到这是一个带有常数的线性递推关系。先求对应线性齐次方程的通解,然后求一个特解,然后组合起来就好了(还记得常微分方程吧,与那个类似)
对应的特征方程是x*x=x+2,两个特征根是2与-1
设f[n]=c1*2^n+c2*(-1)^n+c,代入递推f[n]=f[n-1]+2*f[n-2]+1
那么,因为2和-1是那个特征方程的特征跟,所以c1,c2以及含幂的项都抵消了,所以
c=c+2*c+1
所以c=-1/2,再讲f[0],f[1]代入,解得f[n]= -(-1)^n/6+2^(n+1)/3-1/2,与生成函数的一样。
求出公式之后,把分母变成逆元,把幂模掉phi(p),模平方乘法都不需要,因为p只有10000量级,乘以不到100个数。
--反正我没看懂,太渣了!
然后ORZ月月鸟的矩阵快速米!
构造一个这样的矩阵{1 2 1
1 0 0
0 0 1}
然后矩阵的N次幂就OK了,构造矩阵真是一个大学问;
PS:答案就是矩阵中MP[0][0]+MP[0][2]的值;具体看代码(虽然这是不好的风格,我说不上来)
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> #include<string> using namespace std; #define inf 19999999 #define N 30000 typedef long long ll; struct matrix { int a[4][4]; }re,rx; int n; matrix mul(matrix x,matrix y)//矩阵快速米 { matrix tep; memset(tep.a,0,sizeof(tep.a)); for (int i=0;i<3;i++) for (int j=0;j<3;j++){ for (int k=0;k<3;k++) tep.a[i][j]+=x.a[i][k]*y.a[k][j]; tep.a[i][j]%=10007; } return tep; } void calc(int n) { while (n) { if (n&1) rx=mul(rx,re); n>>=1; re=mul(re,re); } printf("%d\n",(rx.a[0][0]+rx.a[0][2])%10007);//求值的操作 } int main() { while (scanf("%d",&n)!=EOF){ memset(re.a,0,sizeof(re.a)); memset(rx.a,0,sizeof(rx.a)); re.a[0][0]=1; re.a[0][1]=2; re.a[0][2]=1;//初始矩阵 re.a[1][0]=1; re.a[2][2]=1; rx.a[0][0]=1; rx.a[1][1]=1; rx.a[2][2]=1;//我构造了一个单位矩阵,方便后面的处理 n--;//-1是因为我们从3开始的 calc(n); } return 0; }
ORZ能找周期的ZZ,真是什么姿势A题的都有
一道PK赛题