【HDU6198 2017 ACM ICPC Asia Regional Shenyang Online E】【找规律 + 矩阵快速幂 + 粗略证明】number number number 无法用K

来源:互联网 发布:淘宝个人店铺 发票 编辑:程序博客网 时间:2024/06/10 21:11

number number number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 235    Accepted Submission(s): 151


Problem Description
We define a sequence F:

 F0=0,F1=1;
 Fn=Fn1+Fn2 (n2).

Give you an integer k, if a positive number n can be expressed by
n=Fa1+Fa2+...+Fak where 0a1a2ak, this positive number is mjfgood. Otherwise, this positive number is mjfbad.
Now, give you an integer k, you task is to find the minimal positive mjfbad number.
The answer may be too large. Please print the answer modulo 998244353.
 

Input
There are about 500 test cases, end up with EOF.
Each test case includes an integer k which is described above. (1k109)
 

Output
For each case, output the minimal mjfbad number mod 998244353.
 

Sample Input
1
 

Sample Output
4
 

Source
2017 ACM/ICPC Asia Regional Shenyang Online

#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }#define MS(x, y) memset(x, y, sizeof(x))#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }int casenum, casei;int K;int fib[N];bitset<100010>f[24];void table(){fib[0] = 0; fib[1] = 1;for (int i = 2; i <= 30; ++i){fib[i] = fib[i - 1] + fib[i - 2];}f[0][0] = 1;for (int i = 0; i <= 20; ++i){for (int k = 0; k <= 30; ++k){f[i + 1] |= (f[i] << fib[k]);}for (int j = 1; j < 100000; ++j)if (!f[i][j]){printf("%d %d\n", i, j);break;}}}namespace FAST_MATRIX{#define rep(i) for(int i = 0; i < G; ++i)#define matrix0(a) rep(i)rep(j)a[i][j] = 0;const int G = 2;int a[G][G], b[G][G], c[G][G];void mul(int a[][G], int b[][G], int c[][G]){static int tmp[G][G];matrix0(tmp);rep(i)rep(j)rep(k)tmp[i][j] = (tmp[i][j] + (LL)a[i][k] * b[k][j]) % Z;rep(i)rep(j)c[i][j] = tmp[i][j];}void qpow(int x[][G], int y[][G], LL p){matrix0(y);rep(i)y[i][i] = 1;while (p){if (p & 1)mul(x, y, y);mul(x, x, x);p >>= 1;}}void solve(int K){matrix0(a); a[0][1] = 1;b[0][0] = 0; b[0][1] = 1;b[1][0] = 1; b[1][1] = 1;qpow(b, c, K * 2 + 3);mul(a, c, b);printf("%d\n", (b[0][0] + Z - 1) % Z);}}int main(){//table();while(~scanf("%d", &K)){FAST_MATRIX::solve(K);//printf("%d\n", DU::solve(K));}return 0;}/*【trick&&吐槽】找规律要不一定要盲目做,可以适当考虑结合其它数列一起做考虑。【题意】输入一个K(1e9)范围的数,让你求出,无法用K个斐波那契数表示的最小整数。【分析】这道题打表可以发现前几项的答案是项数0123456714123388232609但是只从这些数上找递推关系好难啊。郑经诗这次发现规律好快呀——我们只要与斐波那契数列一起考虑就好啦!斐波那契01123581321345589发现没有?ans[i] = fib[i * 2 + 3] - 1于是一个矩阵快速幂就可以解决这道题。输入K,则求fib[K * 2 + 3]============================================================fibonacci 矩阵初始态a:[0 1]转移态b:[0 1][1 1]最终:c = a * (b ^ (K * 2 + 3))c.v[0][0]就是答案============================================================证明——我们再考虑一下这道题的证明:假如说,我们用K个数不构成的最小整数为X,且X = fib[x] - 1并且有fib[x] + fib[y] = fib[z]那么现在有了第K+1个斐波那契数,我们要证明[1, fib[z] - 2]的正整数都可以构成,而fib[z] - 1恰好不行。因为[1, fib[x] - 2]都可以构成呀,所以加上fib[y],显然[1, fib[z] - 2]都可以构成。那么,为什么fib[z] - 1构成不了呢?1,如果选了fib[y],则因为其他K个数构不成fib[x] - 1,于是整体上无法构成fib[z] - 12,如果不选fib[y](即不选f[z-1]),我们发现——要至少使用K+1个数才能构成fib[z-1] - 1fib[z-1] - 1 + f[z-1] == f[z],这里至少要还要一个f[z-1],但是已经说了不取了,而f[z-1]要至少2个数,GG要至少使用K-1个数才能构成fib[z-2] - 1fib[z-2] - 1 + f[z-2]+f[z-2] == f[z],这里至少要还要两个f[z-2],但是已经说了不取了,而构成一个f[z-2]要也至少2个数,GG要至少使用K-2个数才能构成fib[z-3] - 1fib[z-3] - 1 + f[z-3]+f[z-3]+... == f[z],发现数量依然是不够的。总之,就GG了……【时间复杂度&&优化】O(8 * log(K))*/



阅读全文
0 0
原创粉丝点击