bon

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  46 Posts :: 0 Stories :: 12 Comments :: 0 Trackbacks

常用链接

留言簿(2)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

poj 2748

这道题跟Fibonacci在解法上一样,不过这道题特殊的地方在于测试数据非常多,用普通的做法(t*log200000000)会超时。

推导到这一步:f[i]=3*f[i-1]-f[i-2],其中f[i]是输入i时的解。
最朴素的办法就是对每个i都从0开始递推。这样最坏复杂度是O(t*200000000)。
改进的办法是,将递推式写成矩阵相乘的式子,具体见借助矩阵快速计算总结与。

代码还是比较简单的:
 1 // 2748 matrix formula
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 int first[2]={1,1};
 8 int trans[2][2]={{3,-1},{1,0}};
 9 __int64 tmp[31][2][2];
10 __int64 p[31];
11 int e[31];
12 int a[10000000];
13 
14 void init()
15 {
16     p[0]=1;
17     int i,j;
18     for(i=1;i<=30;i++) p[i]=2*p[i-1];
19     tmp[0][0][0]=3,tmp[0][0][1]=-1,tmp[0][1][0]=1,tmp[0][1][1]=0;
20     for(i=1;i<=30;i++){
21         tmp[i][0][0]=(tmp[i-1][0][0]*tmp[i-1][0][0]+tmp[i-1][0][1]*tmp[i-1][1][0])%100000;
22         tmp[i][0][1]=(tmp[i-1][0][0]*tmp[i-1][0][1]+tmp[i-1][0][1]*tmp[i-1][1][1])%100000;
23         tmp[i][1][0]=(tmp[i-1][1][0]*tmp[i-1][0][0]+tmp[i-1][1][1]*tmp[i-1][1][0])%100000;
24         tmp[i][1][1]=(tmp[i-1][1][0]*tmp[i-1][0][1]+tmp[i-1][1][1]*tmp[i-1][1][1])%100000;
25     }
26     a[0]=1;
27     a[1]=1;
28     for(i=2;i<10000000;i++){
29         a[i]=(3*a[i-1]-a[i-2]+200000)%100000;
30     }
31 }
32 
33 int solve(int n)
34 {
35     memset(e,0,sizeof(e));
36     int nn=n;
37     int i=0;
38     while(nn!=0){
39         int x=nn%2;
40         nn/=2;
41         e[i++]=x;
42     }
43     __int64 res[2][2]={{1,0},{0,1}},t[2][2];
44 
45     for(i=0;i<=30;i++){
46         if(e[i]){
47             t[0][0]=res[0][0]*tmp[i][0][0]+res[0][1]*tmp[i][1][0];
48             t[0][1]=res[0][0]*tmp[i][0][1]+res[0][1]*tmp[i][1][1];
49             t[1][0]=res[1][0]*tmp[i][0][0]+res[1][1]*tmp[i][1][0];
50             t[1][1]=res[1][0]*tmp[i][0][1]+res[1][1]*tmp[i][1][1];
51             res[0][0]=t[0][0]%100000,res[0][1]=t[0][1]%100000,res[1][0]=t[1][0]%100000,res[1][1]=t[1][1]%100000;
52         }
53     }
54     
55     int ans=(res[0][0]+res[0][1]+200000)%100000;
56     printf("%d\n",ans);
57     return ans;
58 }
59 
60 int main()
61 {
62     //printf("%d\n",(-11)%10);
63     init();
64     int t,n;
65     /*
66     scanf("%d",&t);
67     while(t--){
68         scanf("%d",&n);
69         if(n<10000000) printf("%d\n",a[n]);
70         else solve(n-1);
71     }
72     */
73     int x,y;
74     for(int i=2;i<2000000000;i++){
75         if(i<10000000) {x=y,y=a[i];}
76         else {x=y;y=solve(i-1);}
77         if(x==1 && y==1){printf("period=%d\n",i);break;}
78     }
79     return 1;
80 }


最后还是看了discuss里的解法,f[i]其实是以75000为循环节:f[75000]=f[0],f[75001]=f[1]且f是2阶的递推式。编程算出前10000000个数,然后逐个枚举就能找出循环节。

这道题给我影响深刻的地方在于可以找循环节。

代码非常简单:
 1 // 2748 matrix formula
 2 
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 int a[75000];
 8 
 9 void init()
10 {
11     a[0]=1;
12     a[1]=1;
13     for(int i=2;i<75000;i++){
14         a[i]=(3*a[i-1]-a[i-2]+200000)%100000;
15     }
16 }
17 int main()
18 {
19     init();
20     __int64 t,n;
21     scanf("%I64d",&t);
22     while(t--){
23         scanf("%I64d",&n);
24         if(n<75000) printf("%d\n",a[n]);
25         else printf("%d\n",a[n%75000]);
26     }
27     return 1;
28 }
posted on 2008-06-09 15:29 bon 阅读(581) 评论(0)  编辑 收藏 引用 所属分类: Programming Contest

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


Google PageRank 
Checker - Page Rank Calculator