圆盘染色

圆盘染色

  大致题意 : 给你一个圆,分成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.奇数在取模后有减法,记得二次取模。

posted @ 2017-11-17 11:01  JZYshuraK_彧  阅读(683)  评论(0编辑  收藏  举报