HDU 5167 Fibonacci 筛法+乱搞

题目链接:

hdu: http://acm.hdu.edu.cn/showproblem.php?pid=5167

题意:

给你一个x,判断x能不能由斐波那契数列中的数相乘得到(一个数可以重复使用)

题解:

1、筛法

首先,小于10^9的斐波那契数很少,就42个(不包括0,1),对于给定的x能同时成为它的因子的斐波那契数更少,所以可以暴力考虑所有能整除x的斐波那契数组成的集合的所有子集。

但是,对于每个子集做筛法的时候必须从大的数开始筛(质因数分解可以随便筛是因为一个数的质因数分解具有唯一性,但这里并不具有唯一性),因为大的数比小的数更特别,它可能具有小的数不具备的组成x的质因子,如果它具备独特质因子,那它就要筛到不能筛为止,如果它不具备独特质因子,它多筛了也不影响的,所以从大到小的做保证了正确的分解不会丢失。

68=2*34=2*2*17,如果从小到大筛,会把2全筛了,剩下个17是没办法筛掉的,而如从后往前则会先筛掉34,再筛掉一个2,这样就可以了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 const int maxn = 111;
 9 
10 int fib[maxn];
11 
12 int tot;
13 void get_fib() {
14     fib[0] = 2, fib[1] = 3;
15     for (tot = 2;; tot++) {
16         fib[tot] = fib[tot - 1] + fib[tot - 2];
17         if (fib[tot] >1000000000) break;
18     }
19 }
20 
21 int di[maxn], n;
22 
23 void init() {
24     n = 0;
25 }
26 
27 int main() {
28     get_fib();
29     int tc;
30     scanf("%d", &tc);
31     while (tc--) {
32         init();
33         int x;
34         scanf("%d", &x);
35         if (x == 0||x==1) {
36             puts("Yes"); continue;
37         }
38         for (int i = 0; i < tot; i++) {
39             if (x%fib[i] == 0) {
40                 di[n++] = fib[i];
41             }
42         }
43         bool su = false;
44         for (int stat = 0; stat < (1 << n); stat++) {
45             int tmp = x;
46             for (int i = n-1; i >=0; i--) {
47                 if (stat&(1 << i)) {
48                     while (tmp%di[i] == 0) tmp /= di[i];
49                 }
50             }
51             if (tmp == 1) {
52                 su = true; break;
53             }
54         }
55         if (su) puts("Yes");
56         else puts("No");
57     }
58     return 0;
59 }
60 /*
61 68
62 */

 2、直接暴搜

看完题解哭晕。。

而且跑的溜溜的orz

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 const int maxn = 111;
 9 
10 int fib[maxn];
11 
12 int tot;
13 void get_fib() {
14     fib[0] = 2, fib[1] = 3;
15     for (tot = 2;; tot++) {
16         fib[tot] = fib[tot - 1] + fib[tot - 2];
17         if (fib[tot] >1000000000) break;
18     }
19 }
20 
21 int di[maxn], n;
22 
23 bool dfs(int cur, int x) {
24     if (x == 1) return true;
25     if (cur == n) return false;
26     if (dfs(cur + 1, x)) return true;
27 
28     if (x%di[cur]==0) {
29         int tmp = x;
30         while (tmp%di[cur] == 0) {
31             tmp /= di[cur];
32             //printf("tmp:%d\n", tmp);
33             if (dfs(cur + 1, tmp)) return true;
34         }
35     }
36     return false;
37 }
38 
39 void init() {
40     n = 0;
41 }
42 
43 int main() {
44     get_fib();
45     int tc;
46     scanf("%d", &tc);
47     while (tc--) {
48         init();
49         int x;
50         scanf("%d", &x);
51         if (x == 0||x==1) {
52             puts("Yes"); continue;
53         }
54         for (int i = 0; i < tot; i++) {
55             if (x%fib[i] == 0) {
56                 di[n++] = fib[i];
57             }
58         }
59         //printf("n:%d\n", n);
60         if (dfs(0,x)) puts("Yes");
61         else puts("No");
62     }
63     return 0;
64 }

 

转载于:https://www.cnblogs.com/fenice/p/5441710.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值