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

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

#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|1
typedef 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个斐波那契数表示的最小整数。

【分析】
这道题打表可以发现前几项的答案是

项数		0	1	2	3	4	5	6	7
		1	4	12	33	88	232	609

但是只从这些数上找递推关系好难啊。
郑经诗这次发现规律好快呀——我们只要与斐波那契数列一起考虑就好啦!

斐波那契	0	1	1	2	3	5	8	13	21	34	55	89
发现没有?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] - 1
2,如果不选fib[y](即不选f[z-1]),
	我们发现——
		要至少使用K+1个数才能构成fib[z-1] - 1
			fib[z-1] - 1 + f[z-1] == f[z],这里至少要还要一个f[z-1],但是已经说了不取了,而f[z-1]要至少2个数,GG
		要至少使用K-1个数才能构成fib[z-2] - 1
			fib[z-2] - 1 + f[z-2]+f[z-2] == f[z],这里至少要还要两个f[z-2],但是已经说了不取了,而构成一个f[z-2]要也至少2个数,GG
		要至少使用K-2个数才能构成fib[z-3] - 1
			fib[z-3] - 1 + f[z-3]+f[z-3]+... == f[z],发现数量依然是不够的。总之,就GG了……

【时间复杂度&&优化】
O(8 * log(K))

*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值