圆盘染色
圆盘染色
大致题意 : 给你一个圆,分成n个扇形,每个扇形可以涂成3个颜色中的一种,但相邻者颜色不同,问有多少种方案。
注释:圆盘不可以转动。数据范围,t<=10000 , n<=10^9其中,t组数据。
这题是容易的,我们先用一种简单的想法:选取一个起始扇形,它有3种方法,那么,顺时针枚举的所有扇形都有2种染色方法,但这个想法到了第n个扇形的时候就会出现问题,因为我们并不知道第n-1个扇形的颜色和起始扇形的颜色,这样的话,我们无法确定最后一个扇形的染色方案数。所以,我们换一种想法。
如果我们已经知道了前i个扇形的染色方案数,是否可以推出第i+1种?想到递推处理。我们记录dp [ i ] 表示i个扇形的方案数。
我们考虑方案数的一个分划——第n-2个圆盘是否与起始圆盘的颜色相同?
若不相同,那么第n-1个圆盘的染色方案只有一种,这个时候,即使将第n-1个圆盘去掉,剩下的n-1个圆盘也是满足条件的,所以,这时的方案不多于a [ n-1 ] ,对应的,a [ n-1 ] 中的每一个方案,我都可以在起始扇形与第n-1个扇形之间塞进一个满足条件的,这样的方案不少于a [ n-1 ] 所以,此时有a [ n-1 ] 种方案。
若相同,那么第n-1个扇形有两种选择。在不考虑第n-1个扇形时,可以将第n-2个扇形和起始扇形捏成一个大扇形,这时的方案数为a [ n-2 ],而且第n-1种用两种染色方案,所以,这时共有2 * a [ n - 2 ] 种方案。所以,递推式为:a [n]=a[n-1] + 2 * a[n-2]。
但是,由于庞大的数据量,承受不住O(n)的时间复杂度。故,我们可以通过求解特征方程求数列通项。解得:a[n]=2^n+2*(-1)^n ( n>1 ) , a[n]=3 ( n=1 ) 然后快速幂就可以了啊!
这道题也可以矩乘,在此不赘述。
附上丑陋的代码...
1 #include <iostream> 2 #include <cstdio> 3 #define mod 12345678 4 using namespace std; 5 typedef long long ll; 6 ll qp(ll a,int b) 7 { 8 a%=mod; 9 ll ans=1; 10 while(b) 11 { 12 if(b&1) ans=(ans*a)%mod; 13 b>>=1; 14 a=(a*a)%mod; 15 } 16 return ans; 17 } 18 int main() 19 { 20 int t; 21 scanf("%d",&t); 22 for(int i=1;i<=t;i++) 23 { 24 int n; 25 scanf("%d",&n); 26 if(n==1) printf("3\n"); 27 else if(n%2) printf("%lld\n",(qp(2,n)-2+mod)%mod); 28 else printf("%lld\n",qp(2,n)+2); 29 } 30 }
小结:
1.没开long long直接爆蛋。
2.忘记了多组数据,直接爆蛋。
3.奇数在取模后有减法,记得二次取模。
| 欢迎来原网站坐坐! >原文链接<