zoukankan      html  css  js  c++  java
  • Codeforces 575A. Fibonotci(矩阵乘法)

    Codeforces 575A. Fibonotci

    题目大意

    • 给出一个递推式: F n = s n − 1 ∗ F n − 1 + s n − 2 ∗ F n − 2 F_n=s_{n-1}*F_{n-1}+s_{n-2}*F_{n-2} Fn=sn1Fn1+sn2Fn2
    • F 0 = 0 F_0=0 F0=0 F 1 = 1 F_1=1 F1=1.
    • s s s的值有周期性,除特殊限制外 s i = s i m o d    N s_i=s_{imod N} si=simodN
    • 特殊限制有 m m m组,每组的形式为将 s j s_j sj改为 v v v,其中 j ≥ N j≥N jN(即特殊情况不会第一段循环节内),
    • F k m o d    P F_kmod P FkmodP.
    • N , M ≤ 5 ∗ 1 0 4 N,M≤5*10^4 N,M5104
    • P , s i , v ≤ 1 0 9 P,s_i,v≤10^9 P,si,v109
    • k , j ≤ 1 0 18 k,j≤10^{18} k,j1018

    题解

    • 如果没有特殊限制,看到 k k k那么大,直接就会想到矩阵乘法,
    • 由于每一位的系数不一样,可以先用倍增求出不同位下( < N <N <N)向右 2 i 2^i 2i步的转移矩阵( 2 ∗ 2 2*2 22),然后直接倍增做即可。
    • 但是有特殊限制的话,该怎么办呢?
    • 其实方法也是类似的,只是矩乘不是一次做到底,而是每次碰到一个限制就停下来,然后对于特殊限制,直接往后计算两位,因为被修改的值在计算 s n + 1 s_{n+1} sn+1 s n + 2 s_{n+2} sn+2时都需要,
    • 当然会有一些要注意的地方,比如出现连续的限制,那么中间一次矩乘都不能做,而是要把一连串的限制都计算完后,再继续做矩乘。
    • 预处理复杂度 O ( N log ⁡ 2 k ) O(Nlog_2k) O(Nlog2k),矩乘总复杂度 O ( N log ⁡ 2 k ) O(Nlog_2k) O(Nlog2k)

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 50010
    ll a[N], f[N][62][2][2];
    struct node {
    	ll x, s;
    }c[N];
    int cmp(node x, node y) {
    	return x.x < y.x;
    }
    int main() {
    	ll K, P, i, j;
    	int n, m; 
    	scanf("%lld%lld", &K, &P);
    	scanf("%d", &n);
    	for(i = 0; i < n; i++) scanf("%lld", &a[i]);
    	scanf("%d", &m);
    	for(i = 1; i <= m; i++) scanf("%lld%lld", &c[i].x, &c[i].s);
    	m++;
    	c[m].x = K + 1, c[m].s = 0;
    	sort(c + 1, c + m + 1, cmp);
    	for(i = 0; i < n; i++) {
    		f[i][0][0][0] = 0;
    		f[i][0][1][0] = 1;
    		f[i][0][0][1] = a[(i - 1 + n) % n];;
    		f[i][0][1][1] = a[i];
    	}
    	for(j = 1; j < 62; j++) {
    		for(i = 0; i < n; i++) {
    			ll k = (i + (1ll << (j - 1))) % n;
    			f[i][j][0][0] = (f[i][j - 1][0][1] * f[k][j - 1][1][0] + f[i][j - 1][0][0] * f[k][j - 1][0][0]) % P;
    			f[i][j][0][1] = (f[i][j - 1][0][1] * f[k][j - 1][1][1] + f[i][j - 1][0][0] * f[k][j - 1][0][1]) % P;
    			f[i][j][1][0] = (f[i][j - 1][1][1] * f[k][j - 1][1][0] + f[i][j - 1][1][0] * f[k][j - 1][0][0]) % P;
    			f[i][j][1][1] = (f[i][j - 1][1][1] * f[k][j - 1][1][1] + f[i][j - 1][1][0] * f[k][j - 1][0][1]) % P;
    		}
    	}
    	ll la = 1;
    	ll s0 = 0, s1 = 1;
    	for(i = 1; i <= m; i++) {
    		ll t = c[i].x, p = t - la, x = la;
    		ll g[2][2], h[2][2];
    		g[0][0] = g[1][1] = 1, g[0][1] = g[1][0] = 0;
    		for(j = 61; j >= 0; j--) if(p >= (1ll << j)) {
    			p -= 1ll << j;
    			h[0][0] = (g[0][1] * f[x % n][j][1][0] + g[0][0] * f[x % n][j][0][0]) % P;
    			h[0][1] = (g[0][1] * f[x % n][j][1][1] + g[0][0] * f[x % n][j][0][1]) % P;
    			h[1][0] = (g[1][1] * f[x % n][j][1][0] + g[1][0] * f[x % n][j][0][0]) % P;
    			h[1][1] = (g[1][1] * f[x % n][j][1][1] + g[1][0] * f[x % n][j][0][1]) % P;
    			g[0][0] = h[0][0], g[1][0] = h[1][0], g[0][1] = h[0][1], g[1][1] = h[1][1];
    			x += 1ll << j;	
    		}
    		ll t0 = (s0 * g[0][0] + s1 * g[1][0]) % P, t1 = (s0 * g[0][1] + s1 * g[1][1]) % P;
    		if(t == K + 1) {
    			printf("%lld
    ", t0 % P);
    			break;
    		}
    		s1 = (t0 * a[(t - 1 + n) % n] + t1 * c[i].s) % P;
    		s0 = t1 % P;
    		la = t + 1;
    		while(c[i + 1].x == c[i].x + 1) {
    			ll s2 = (s0 * c[i].s + s1 * c[i + 1].s) % P;
    			s0 = s1, s1 = s2;
    			la++;
    			if(la == K) {
    				printf("%lld
    ", s1);
    				return 0;
    			}
    			i++;
    		}
    		ll s2 = (s0 * c[i].s + s1 * a[la % n]) % P;	
    		s0 = s1, s1 = s2;
    		la++;
    		if(la == K) {
    			printf("%lld
    ", s1);
    			break;
    		}
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    正则表达式
    javascript if(条件)------------条件中可以使用的值
    maven配置
    获取中文日期
    Oracle无安装客户端安装方法
    Eclipse org.eclipse.compare plug-in
    Differences or similarities between Java and C++
    Java Programming Guidelines
    Native Method
    Object in Java same as pointer
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910025.html
Copyright © 2011-2022 走看看