Power Calculus 快速幂计算 (IDA*/打表)

原题:1374 - Power Calculus


题意:

最少用几次乘法或除法,可以从x得到x^n。(每次只能从已经得到的数字里选择两个进行操作)


举例:

x^31可以通过最少6次操作得到(5次乘,1次除)

x^2 = x*x

x^4 = (x^2)*(x^2)

x^8 = (x^4)*(x^4)

x^16 = (x^8)*(x^8)

x^32 = (x^16)*(x^16)

x^31 = (x^32)÷x


分析:

可以看到,每次从已得到的数字中选取两个操作,这样就有了枚举的思路。

这道题又是没有明显的枚举次数上限,所以很自然想到了用迭代加深搜索算法。

因为n的数据范围是1~1000,所以可以通过计算,预设最大的枚举层次数上限MAXD是13.

而且可以发现如果当前的数字num*2^(MAXD-d) < n,就没有继续搜的必要了,回溯(num是通过前d步得到的数字)

所以我们的IDA*算法思路基本上就完全了。


进一步优化:

如果只依靠上述的思路,写出来的程序要跑2.7s(上限是3s),所以属于刚刚好AC.

我们这里有很多种优化方法,我就说两个我用了的。

1. 寻找幂的时候,我们每次不应该从已得到数字里任意抽两个,这样效率很低。而且很容易出一道,我们每一次都是操作上一步得到的数字,所以这样只需要枚举另一个操作数就够了。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 const int MAXD = 13;
 5 int n, f[1<<(MAXD - 1)], maxd, a[15];
 6
 7 bool dfs(int d) {
 8     if (a[d] == n) return true;
 9     if (d < maxd && (a[d]<<(maxd - d)) >= n) {
10         for (int i = d; i >= 0; i--)
11             for (int j = 0; j < 2; j++) {
12             int nextn = j ? a[d] + a[i] : a[d] - a[d - i];
13             if (nextn <= 0 || f[nextn]) continue;
14             f[nextn] = 1;
15             if (nextn <= 0) continue;
16             a[d + 1] = nextn;
17             if (dfs(d + 1)) return true;
18             f[nextn] = 0;
19         }
20     }
21     return false;
22 }
23 int main() {
24     a[0] = 1;
25     while (scanf("%d", &n) == 1 && n) {
26         if (n == 1) { printf("0\n"); continue;}
27         for (maxd = 1; maxd < MAXD; maxd++) {
28             memset(f, 0, sizeof(f));
29             f[1] = 1;
30             if (dfs(0)) break;
31         }
32         printf("%d\n", maxd);
33     }
34     return 0;
35 }

2.打表。

因为n的范围是1~1000, 所以我们可以用稍微慢一点的算法,提前算出来结果,保存到文件里,然后再粘贴到提交的代码里。

比如我的代码是

    

 1 int main() {
 2     freopen("ans_table", "w", stdout);
 3     /*
 4         some code.
 5     */
 6     for(n = 1; n <= 1000; n++) {
 7         if (n == 1) { printf("ans[%d] = 0;\n", i); continue;}
 8         for (maxd = 1; maxd < MAXD; maxd++) {
 9         /*
10             some code.
11         */
12             if (dfs(0, 1)) break;
13         }
14         printf("ans[%d] = %d;\n", i, maxd);
15     }
16     return 0;
17 }

这样我们就本地生成了文件"ans_table"。

里面的答案都是形如

ans[1] = 0;
ans[2] = 1;
ans[3] = 2;
ans[4] = 2;
ans[5] = 3;
ans[6] = 3;
ans[7] = 4;
ans[8] = 3;
ans[9] = 4;
ans[10] = 4;
ans[11] = 5;
ans[12] = 4;

相当于直接生成代码形式的表格。

    速度自然是0ms

时间: 2024-10-01 01:49:55

Power Calculus 快速幂计算 (IDA*/打表)的相关文章

矩阵快速幂计算hdu1575

矩阵快速幂计算和整数快速幂计算相同.在计算A^7时,7的二进制为111,从而A^7=A^(1+2+4)=A*A^2*A^4.而A^2可以由A*A得到,A^4可以由A^2*A^2得到.计算两个n阶方阵的乘积复杂度为O(n^3).k的二进制大约有logk位,总的复杂度为O(n^3*logk). #define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<queue> #include<iomanip> #incl

快速幂计算(整数快速幂/矩阵快速幂)

库函数pow是用朴素算法对浮点型数据进行幂运算的,时间复杂度为o(n),计算比较大的数可能会超时和数据溢出: //*************快速幂计算**************************************** 朴素算法实现: ll get_pow(ll x, ll n)  //** (这里的n要求不小于0,如果n小于0则令n=-n,并且最终返回1.0/ans即可){    ll ans=1;    while(n--)    {        ans*=x%MAX;    

uva 1374 快速幂计算

#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <cstdlib> #include <stack> #include <cctype> #include <string> #include <malloc.h> #include

UVa 1374 - Power Calculus——[迭代加深搜索、快速幂]

解题思路: 这是一道以快速幂计算为原理的题,实际上也属于求最短路径的题目类型.那么我们可以以当前求出的幂的集合为状态,采用IDA*方法即可求解.问题的关键在于如何剪枝效率更高.笔者采用的剪枝方法是: 1)如果当前状态幂集合中的最大元素max满足 max*2^(maxd-cur_d)<n,则剪枝.原因是:在每一次状态转移后,max最多增大一倍.(maxd-cur_d)次转移之后,max最多变成原来的2^(maxd-cur_d)倍,然而如果当前状态的极限情况下仍有max<n,则当前状态结点一定无法

UVa 11149 Power of Matrix (矩阵快速幂,倍增法或构造矩阵)

题意:求A + A^2 + A^3 + ... + A^m. 析:主要是两种方式,第一种是倍增法,把A + A^2 + A^3 + ... + A^m,拆成两部分,一部分是(E + A^(m/2))(A + A^2 + A^3 + ... + A^(m/2)),然后依次计算下去,就可以分解,logn的复杂度分解,注意要分奇偶. 另一种是直接构造矩阵,,然后就可以用辞阵快速幂计算了,注意要用分块矩阵的乘法. 代码如下: 倍增法: #pragma comment(linker, "/STACK:10

POJ 3070 Fibonacci(矩阵快速幂模板)

Description: In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, … An alternative formula for the Fibonacci sequence i

AtCoder AGC031D A Sequence of Permutations (群论、置换快速幂)

题目链接 https://atcoder.jp/contests/agc031/tasks/agc031_d 题解 这居然真的是个找规律神题... 首先要明白置换的一些基本定义,置换\(p\)和\(q\)的复合\(a\)定义为\(a_i=p_{q_i}\), 记作\(a=pq\). 有定理\((pq)^{-1}=q^{-1}p^{-1}\). 显然题目里定义的\(f(p,q)=qp^{-1}\). 然后打表打出前几项: \(a_1=p\) \(a_2=q\) \(a_3=qp^{-1}\) \(

算法笔记--矩阵快速幂

写的不错的博客:http://www.cnblogs.com/yan-boy/archive/2012/11/29/2795294.html 优点:根据数列递推式快速计算数列an的值(当n很大时) 步骤:由数列递推式构造矩阵,然后用矩阵快速幂计算矩阵的幂. 构造矩阵:对于an =x*an-1 +y*an-2 ,可以构造矩阵为: [an ,an-1]=[an-1 ,an-2]*A A=[x 1 y 0]; 矩阵快速幂模板: #include<iostream> #include<cstri

HDOJ 5411 CRB and Puzzle 矩阵快速幂

直接构造矩阵,最上面一行加一排1.快速幂计算矩阵的m次方,统计第一行的和 CRB and Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 133    Accepted Submission(s): 63 Problem Description CRB is now playing Jigsaw Puzzle. There