zoukankan      html  css  js  c++  java
  • DP + math 之 Codeforces 126D

    //  [7/12/2014 Sjm]
    /*
    题目:
    By the given number n determine the number of its possible different decompositions into Fibonacci sum.
     
    前提:
    1) F[86] 是 >=10^18 的最大Fibonacci数;
    2)
    (由Fibonacci数列的构造式决定,举几个例子就可以知道了)
    假设的Fibonacci数的下标区间为[m, n),包括 m, 对n进行拆分,其分解的数目是: (n-m)>>1
    假设的Fibonacci数的下标区间为(m, n),不包括 m, 对n进行拆分,其分解的数目是: (n-m-1)>>1
     
    思路:
    用 N 减去(与N相等或小于N)的最大的Fibonacci数,并将得到的值付给N,不断循环,直至 N 为零。
    (保证拆分出来的Fibonacci数的数目是最少的,使 dp 时不会漏掉情况)
     
    将取得的所有Fibonacci数从小到大排列出来, 存储于 get_index[] (存储的是所取得的Fibonacci的标号)
     
    状态:	
    dp[i][1]: 在拆分 N 时,已选取 get_index[i] 位置所代表的Fibonacci数, 此情况下不同分解的数目
    		(言外之意是:不可以将 get_index[i] 位置所代表的Fibonacci数拆了)
    dp[i][0]: 在拆分 N 时,没有选取 get_index[i] 位置所代表的Fibonacci数,此情况下不同分解的数目
    		(言外之意是:可以将 get_index[i] 位置所代表的Fibonacci数用其他Fibonacci数拆了)
     
    分析:   
    1) dp[i][1]的情况: 
    	由于不可以将 get_index[i] 位置所代表的Fibonacci拆数了,
    	故决定dp[i][1]的因素是 get_index[i-1] 位置所代表的Fibonacci数
    		
    2) dp[i][0]的情况:
    	此时 get_index[i] 位置所代表的Fibonacci数可拆,
    	故	在 dp[i-1][0] 的基础上: 需要分解的Fibonacci数下标区间为  [get_index[i-1], get_index[i])
    		在 dp[i-1][1] 的基础上: 需要分解的Fibonacci数下表区间为  (get_index[i-1], get_index[i])
    		(求解方法,参见前提)
    		至于为什么这样分解,可以看一下这样几个例子(关键看从上到下的排列方式):
    		例1:	13 = 13				  例2:	16 = 13 + 3
    			13 = 8 + 5				16 = 13 + 2 + 1
    			13 = 8 + 3 + 2				16 = 8 + 5 + 3
    								16 = 8 + 5 + 2 + 1
    							
    决策:
    	初始状态: dp[0][1] = 1,  dp[0][1] = (get_index[i] - 1)>>1;
    	dp[i][1] = dp[i - 1][1] + dp[i - 1][0];
    	dp[i][0] = dp[i - 1][0] * ((get_index[i] - get_index[i - 1]) >> 1) 
    		 + dp[i - 1][1] * ((get_index[i] - get_index[i - 1] - 1) >> 1);
     
    */
     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 typedef __int64 int64;
     8 const int MAX = 90;
     9 
    10 int64 F[MAX];
    11 int get_index[MAX];
    12 int64 dp[MAX][2];
    13 
    14 void Fib()
    15 {
    16     F[0] = 1;    F[1] = 1;
    17     for (int i = 2; i < 87; ++i) {
    18         F[i] = F[i - 1] + F[i - 2];
    19     }
    20 }
    21 
    22 int64 Solve(int len)
    23 {
    24     dp[0][1] = 1;
    25     dp[0][0] = (get_index[0] - 1) >> 1;
    26     for (int i = 1; i < len; ++i) {
    27         dp[i][1] = dp[i - 1][1] + dp[i - 1][0];
    28         dp[i][0] = 
    29                 dp[i - 1][0] * ((get_index[i] - get_index[i - 1]) >> 1)
    30             +    dp[i - 1][1] * ((get_index[i] - get_index[i - 1] - 1) >> 1);
    31     }
    32     return (dp[len - 1][0] + dp[len - 1][1]);
    33 }
    34 
    35 int main()
    36 {
    37     //freopen("input.txt", "r", stdin);
    38     Fib();
    39     int T;
    40     scanf("%d", &T);
    41     while (T--) {
    42         int64 n;
    43         int len = 0;
    44         scanf("%I64d", &n);
    45         for (int i = 86; i >= 1; --i) {
    46             if (F[i] <= n) {
    47                 n -= F[i];
    48                 get_index[len++] = i;
    49             }
    50         }
    51         if (n) { 
    52             // 若无法将 N 拆分成不等的Fibonacci数之和,输出 0。
    53             //(这里不判断也可以AC,但是目前我无法给出“任何一个正整数都可以用不等的Fibonacci数列表示”的数学证明)
    54             printf("0
    ");
    55             continue;
    56         }
    57         reverse(get_index, get_index + len);
    58         printf("%I64d
    ", Solve(len));
    59     }
    60     return 0;
    61 }
     
  • 相关阅读:
    AddressFamily 枚举指定 Socket 类的实例可以使用的寻址方案
    在.NET开发中灵活使用TreeView控件
    TreeView初始化,返回节点值的方法(转)收藏
    怎样彻底删除系统服务项(转载)
    SQL Server 返回插入记录的自增编号(转)
    Socut.Data.dll 与AspNetPager.dll使用说明及心得体会 (转载)
    ActionScript最新3D引擎项目(转载)
    XP自动搜索功能修复
    Postgresql 重新安装,数据不丢失
    work with postgis & geoserver
  • 原文地址:https://www.cnblogs.com/shijianming/p/4140835.html
Copyright © 2011-2022 走看看