2018北京ICPC D. Frog and Portal 斐波那契数 构造

题目链接:http://hihocoder.com/contest/icpcbeijing2018/problem/4

题意:青蛙可以从p跳到 p+1,p+2,现在青蛙要从0跳到200,你可以安传送门ai-aj 青蛙一到ai就会跳到aj ,可能形成死循环,每个传送门ai不同,

求安传送门后,使青蛙跳到200的方案数正好为m的安放方法

题解:

没做出来。。看的大家的题解,感觉太巧妙了

plana:

任何正整数都可以分解为若干不同斐波那契数之和

f[48]就已经大于1<<32 了,可以从从大到小减去斐波那契数,连得时候倒着连,比如从199-200=1,198-200=2,197-200=3……,然后1连197,3连198,5连197,结束的结点连自己结束6-6

前面隔一个连一个到后面,这样前面每一种方案为1,连到后面后对后面不造成影响。

如先连了1-195 ,又连了3-198,那相当于在198加了1方案,199也加了1方案,200加了2方案,又是一个重新开始的斐波那契,叠加在前一个连得上。

如图

planb:如果我们位于x,方案为m,m为偶数:连接x+1~x+3,x+2~x+3,这样到x+3 方案有2种,变为问题从x+3到200,方案为m/2,

m为奇数,连x+1~200,变为问题从x+2到200 方案为m-1 方案数

特判0,1情况

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int const maxn=210;
 4 typedef long long ll;
 5 long long f[maxn],m,tot,ans[maxn];
 6 void getfi(){
 7     f[200]=1;f[199]=1;
 8     for(int i=198;i>=150;i--)f[i]=f[i+1]+f[i+2];
 9 }
10 void work(){
11     if(m==0){
12         printf("2
1 1
2 1
");return ;
13     }
14     if(m==1){
15         printf("2
1 199
2 2
");return ;
16     }
17     if(m==2){printf("2
1 2
2 199
");return ;}
18     for(ll i=150;i<=199;i++){
19         if(m==0)break;
20         if(m-f[i]>=0){
21             ans[++tot]=i;
22             m-=f[i];
23         }
24     }
25     printf("%lld
",tot+1);
26     for(int i=1;i<=tot;i++)printf("%d %lld
",i*2-1,ans[i]);
27     printf("%lld %lld
",tot*2,tot*2);
28 }
29 int main(){
30     getfi();
31     while(scanf("%lld",&m)!=EOF){
32         tot=0;
33         work();
34     }
35     return 0;
36 }
原文地址:https://www.cnblogs.com/conver/p/11291000.html