UVa Problem Solution: 10254 - The Priest Mathematician
2008-12-04 13:18
706 查看
From the description of this problem we can easily draw the recurrence of
f(n) = 2*f(n-k) + 2^k - 1
and the base cases of
f(0) = 0 and f(1) = 1
However, how can we determine which k would give the minimum value of f(n)?
Suppose k is giving the minimum value, then it must satisfy
2*f(n-k) + 2^k - 1 <= 2*f(n-(k+1)) + 2^(k+1) - 1,
which can be deduced to
f(n-k) - f(n-k-1) <= 2^(k-1).
Thus, let d(n) = f(n) - f(n-1), and we can use d(n) to determine the value
of k through the inequality of
d(n-k) <= 2^(k-1)
and the fact that d(n) is a non-decreasing sequence.
Code:
/***************************************************************************
* Copyright (C) 2008 by Liu Kaipeng *
* LiuKaipeng at gmail dot com *
***************************************************************************/
/* @JUDGE_ID 00000 10254 C++ "The Priest Mathematician" */
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include "big_unsigned.hpp"
using namespace std;
/*
* From the description of this problem we can easily draw the recurrence of
* f(n) = 2*f(n-k) + 2^k - 1
* and the base cases of
* f(0) = 0 and f(1) = 1
* However, how can we determine which k would give the minimum value of f(n)?
* Suppose k is giving the minimum value, then it must satisfy
* 2*f(n-k) + 2^k - 1 <= 2*f(n-(k+1)) + 2^(k+1) - 1,
* which can be deduced to
* f(n-k) - f(n-k-1) <= 2^(k-1).
* Thus, let d(n) = f(n) - f(n-1), and we can use d(n) to determine the value
* of k through the inequality of
* d(n-k) <= 2^(k-1)
* and the fact that d(n) is a non-decreasing sequence.
*/
int const size = 10001;
big_unsigned numbers[size];
big_unsigned pow2[1500];
big_unsigned diff[size];
void gen_numbers()
{
pow2[0] = 1;
for (int n = 1; n < 1500; ++n)
pow2
= pow2[n-1] * 2;
numbers[0] = 0, numbers[1] = 1;
diff[0] = 0, diff[1] = 1;
int k = 1;
for (int n = 2; n < size; ++n) {
if (diff[n-k] > pow2[k-1]) ++k;
numbers
= numbers[n-k] * 2;
numbers
+= pow2[k];
numbers
-= 1;
diff
= numbers
- numbers[n-1];
}
}
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen((string(argv[0]) + ".in").c_str(), "r", stdin);
freopen((string(argv[0]) + ".out").c_str(), "w", stdout);
#endif
gen_numbers();
for (int n; cin >> n; ) cout << numbers
<< '/n';
return 0;
}
f(n) = 2*f(n-k) + 2^k - 1
and the base cases of
f(0) = 0 and f(1) = 1
However, how can we determine which k would give the minimum value of f(n)?
Suppose k is giving the minimum value, then it must satisfy
2*f(n-k) + 2^k - 1 <= 2*f(n-(k+1)) + 2^(k+1) - 1,
which can be deduced to
f(n-k) - f(n-k-1) <= 2^(k-1).
Thus, let d(n) = f(n) - f(n-1), and we can use d(n) to determine the value
of k through the inequality of
d(n-k) <= 2^(k-1)
and the fact that d(n) is a non-decreasing sequence.
Code:
/***************************************************************************
* Copyright (C) 2008 by Liu Kaipeng *
* LiuKaipeng at gmail dot com *
***************************************************************************/
/* @JUDGE_ID 00000 10254 C++ "The Priest Mathematician" */
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include "big_unsigned.hpp"
using namespace std;
/*
* From the description of this problem we can easily draw the recurrence of
* f(n) = 2*f(n-k) + 2^k - 1
* and the base cases of
* f(0) = 0 and f(1) = 1
* However, how can we determine which k would give the minimum value of f(n)?
* Suppose k is giving the minimum value, then it must satisfy
* 2*f(n-k) + 2^k - 1 <= 2*f(n-(k+1)) + 2^(k+1) - 1,
* which can be deduced to
* f(n-k) - f(n-k-1) <= 2^(k-1).
* Thus, let d(n) = f(n) - f(n-1), and we can use d(n) to determine the value
* of k through the inequality of
* d(n-k) <= 2^(k-1)
* and the fact that d(n) is a non-decreasing sequence.
*/
int const size = 10001;
big_unsigned numbers[size];
big_unsigned pow2[1500];
big_unsigned diff[size];
void gen_numbers()
{
pow2[0] = 1;
for (int n = 1; n < 1500; ++n)
pow2
= pow2[n-1] * 2;
numbers[0] = 0, numbers[1] = 1;
diff[0] = 0, diff[1] = 1;
int k = 1;
for (int n = 2; n < size; ++n) {
if (diff[n-k] > pow2[k-1]) ++k;
numbers
= numbers[n-k] * 2;
numbers
+= pow2[k];
numbers
-= 1;
diff
= numbers
- numbers[n-1];
}
}
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen((string(argv[0]) + ".in").c_str(), "r", stdin);
freopen((string(argv[0]) + ".out").c_str(), "w", stdout);
#endif
gen_numbers();
for (int n; cin >> n; ) cout << numbers
<< '/n';
return 0;
}
相关文章推荐
- UVa Problem 10254 The Priest Mathematician (牧师数学家)
- uva 10254 the priest mathematician
- UVA 10254 The Priest Mathematician
- UVA10254 - The Priest Mathematician(找规律)
- UVA 10254 - The Priest Mathematician(规律)
- UVA 10254 The Priest Mathematician
- uva 10254 - The Priest Mathematician(dp)
- UVA 10254 - The Priest Mathematician (dp | 汉诺塔 | 找规律 | 大数)
- uva 10254——The Priest Mathematician
- UVA 10254 - The Priest Mathematician (dp | 汉诺塔 | 找规律 | 大数)
- uva 10254 The Priest Mathematician
- UVA 10254 十八 The Priest Mathematician
- UVa 10254 - The Priest Mathematician (4柱汉诺塔)
- 递推+高精度+找规律 UVA 10254 The Priest Mathematician
- uva 10254 - The Priest Mathematician
- UVA 10254-The Priest Mathematician(大数+递推)
- UVa Problem Solution: 10196 - Check The Check
- UVa Problem Solution: 100 - The 3n+1 problem
- UVA 11389 The Bus Driver Problem(贪心)
- uva729 - The Hamming Distance Problem(Hamming距离问题)