zoukankan      html  css  js  c++  java
  • 递推式的循环问题

    形如 斐波拉契数列 这样的形形色色的递推式 模上一个数M过后的值 是一个循环的效果。

    可以这样解释 拿斐波拉契数列举例 F[i] = F[i - 1] + F[i - 2] ;F[i] 如果模上一个数M可以得到M个结果, 并且是由前两项转移过来的, 那么最多有 M ^ 2 项会出现循环,但往往是小于M ^ 2 的,如果是由前三项转移的话,那么最多经过M ^ 3项后出现循环

    套路一:

    数据允许的范围求循环节

    给出两个非整数a, b, n(0  <= a, b <= 2^64, 1 <= n <= 1000),任务是计算出f(a^b) % n, 其中f[0] = f[1] = 1, f[i] = f[i - 1] + f[i - 2]

    由上面知道最多会有 n ^ 2 项会出现循环,判断出现循环的方法:连续出现 (f[0] : 1, f[1] : 1),因为循环的实质是前两项出现循环,那么方法就很明显了,首先找到关于数列模上n的循环节长度,然后用快速幂计算a ^ b % n,然后就知道a ^ b在一个循环节的哪一项了。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll unsigned long long
    
    const int N = 1e6 + 7;
    ll a, b, n;
    int kase, F[N], M;
    
    ll readll () {
    	ll K = 0; char c = getchar();
    	while (c < '0' || c > '9') c = getchar();
    	while (c >= '0' && c <= '9') K = K * 10 + c - '0',c = getchar();
    	return K;
    }
    
    int pow (ll x,ll y){
    	ll ret = 1;
    	while (y) {
    		if(y & 1) ret = (x * ret) % M;
    		x = (x % M) * (x % M) % M;
    		y >>= 1;
    	}
    	return ret;
    }
    
    int main(){
    	scanf ("%d", &kase);
    	while (kase--) {
    		a = readll(), b = readll(), n = readll();
    		if( !a || n==1 ){puts("0");continue;}
    		F[0] = F[1] = 1;
    		int cur = 2,flag = 0;
    		while (true) {
    			F[cur] = (F[cur-1] + F[cur-2]) % n;
    			if (F[cur] != 1) flag = 0;
    			else if (F[cur] == 1 && flag == 0) flag = 1;
    			else if (F[cur] == 1 && flag == 1) break;
    			++cur;
    		}
    		M = cur - 1;
    		printf("%d
    ", F[(pow(a, b) - 1 + M) % M]);
    	}
    	return 0;
    }
    

      

    套路二

    对于特定的模打表找循环节

    依然拿斐波拉契数列举例,给出一个数字n (<=10^1000),求f[f[i]] % 1e9+7 的数值

    对于f[x] % M 项的数值最坏情况下会出现M ^ 2的循环,但是肯定要找循环节,所以打一个表碰运气看他的循环是多少,根据实践循环节的长度为2e9 + 16,那么在里面的f[i]就模上2e9 + 16,现在转换为f[x] % 2e9 + 16的问题了,一样的打表找循环节,长度为329616,那么n就可以直接模上329616,剩下的就是矩阵的事情了~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define ll long long
    char ch[1050];
    int mod[3];
    struct Matrix {
    	ll map[3][3];
    	void clear () {memset(map, 0, sizeof (map));}
    };
    
    Matrix Mul (Matrix x, Matrix y, int F) {
    	Matrix ret;
    	ret.clear();
    	for (int i = 0; i < 2; ++i) 
    		for (int j = 0; j < 2; ++j)
    			for (int k = 0; k < 2; ++k)
    				ret.map[i][j] = (ret.map[i][j] + x.map[i][k] * y.map[k][j] % mod[F]) % mod[F];
    	return ret;
    }
    
    Matrix Pow (Matrix x, int n, int F) {
    	Matrix ret;
    	ret.clear();
    	ret.map[0][0] = 1;
    	ret.map[1][1] = 1;
    	while (n) {
    		if (n & 1) ret = Mul(ret, x, F);
    		x = Mul(x, x, F);
    		n >>= 1;
    	}
    	return ret;
    }
    
    int main () {
    	int kase;
    	mod[1] = 2e9 + 16, mod[2] = 1e9 + 7, mod[3] = 329616;
    	scanf ("%d", &kase); 
    	while (kase--) {
    		ll n = 0;
    		scanf ("%s", &ch);
    		int len = strlen(ch);
    		for (int i = 0; i < len; ++i) n = (n * 10 % 329616 + ch[i] - '0') % 329616;
    		Matrix ans, ori;
    		ans.clear(), ori.clear();
    		ans.map[0][0] = 0;
    		ans.map[0][1] = 1;
    		ori.map[0][0] = 0;
    		ori.map[0][1] = 1;
    		ori.map[1][0] = 1;
    		ori.map[1][1] = 1;
    		ans = Mul(ans, Pow(ori, n, 1), 1);
    		n = ans.map[0][0];
    		ans.map[0][0] = 0;
    		ans.map[0][1] = 1;
    		ans = Mul(ans, Pow(ori, n, 2), 2);
    		printf ("%d
    ", ans.map[0][0]);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    【LeetCode】Validate Binary Search Tree
    【LeetCode】Search in Rotated Sorted Array II(转)
    【LeetCode】Search in Rotated Sorted Array
    【LeetCode】Set Matrix Zeroes
    【LeetCode】Sqrt(x) (转载)
    【LeetCode】Integer to Roman
    贪心算法
    【LeetCode】Best Time to Buy and Sell Stock III
    【LeetCode】Best Time to Buy and Sell Stock II
    CentOS 6 上安装 pip、setuptools
  • 原文地址:https://www.cnblogs.com/xgtao/p/5964720.html
Copyright © 2011-2022 走看看