zoukankan      html  css  js  c++  java
  • 题解 P3216 【[HNOI2011]数学作业】

    P3216 [HNOI2011]数学作业

    这一道题

    ……

    [nleq 10^{18} ]

    这一看就要用矩阵乘法

    我们先写出递推式

    [f(n+1)=f(n) imes 10^{calc(n+1)}+(n+1) ]

    这其中,calc代表的是n+1在十进制中有多少位

    既然有calc,那么我们自然而然得想到划分

    因为数位是连续的,所以将(19),(1099),(100~999)……(1e17+1,1e18-1)划分成区间

    这时,calc就可以当成定值了

    然后我们就可以写出矩形递推式了

    [egin{bmatrix}f_{n+1}\n+2\1end{bmatrix} = egin{bmatrix} calc&;1&;0 \ 0 &;1&;1 \ 0&;0&;1 end{bmatrix} imes egin{bmatrix}f_{n}\n+1\1end{bmatrix} ]

    然后时间复杂度就是

    [O(log^3(n)) ]

    解决


    #include<cstdio>
    #define Starseven main
    #define ll long long
    ll mod, S[20];
    
    struct matrix {
    	ll va[4][4];
    	int line, cross;
    	void Mem() {
    		for (int i = 1; i <= 3; i++) {
    			for (int j = 1; j <= 3; j++) {
    				va[i][j] = 0;
    			}
    		}
    		return ;
    	}
    };
    
    matrix operator *(const matrix &a, const matrix &b) {
    	matrix c;
    	c.Mem();
    	for (int i = 1; i <= a.line; i++) {
    		for (int k = 1; k <= a.cross; k++) {
    			for (int j = 1; j <= b.cross; j++) {
    				c.va[i][j] = (c.va[i][j] + a.va[i][k] * b.va[k][j] % mod) % mod;
    			}
    		}
    	}
    	c.line = a.line;
    	c.cross = b.cross;
    	return c;
    }
    
    int Starseven(void) {
    	ll n;
    	read(n);
    	read(mod);
    	matrix ans, txt;
    	
    	ans.Mem();
    	ans.va[1][1] = 1;
    	ans.va[2][1] = 2;
    	ans.va[3][1] = 1;
    	ans.line = 3;
    	ans.cross = 1;
    	
    	ll hack = 1;
    	for (int i = 1; i <= 18; i++) {
    		S[i] = hack * 10;
    		S[i] -= hack;
    		hack *= 10; 
    	}
    	hack = 10; 
    	for (ll i = 1; i <= 18; i++) {
    		txt.Mem();
    		
    		txt.va[1][1] = hack % mod;
    		txt.va[1][2] = 1;
    		txt.va[2][2] = 1;
    		txt.va[2][3] = 1;
    		txt.va[3][3] = 1;
    		txt.line = 3;
    		txt.cross = 3;
    		
    		if(n >= S[i]) {
    			ll b = S[i];
    			if(i == 1) b -= 1;
    			while(b) {
    				if(b & 1ll) ans = txt * ans;
    				txt = txt * txt;
    				b >>= 1ll;
    			}
    			n -= S[i];
    		}
    		else {
    			if(i == 1) n -= 1;
    			while(n) {
    				if(n & 1ll) ans = txt * ans;
    				txt = txt * txt;
    				n >>= 1ll;
    			}
    			break;
    		}
    		hack = (hack * 10) % mod;
    	}
    	write(ans.va[1][1]);
    	puts("");
    	return 0;
    } 
    
  • 相关阅读:
    Spring Boot 属性配置和使用
    spring boot下WebSocket消息推送
    深入理解分布式事务,高并发下分布式事务的解决方案
    HashMap实现原理分析
    JVM 简述
    Java 并发之原子性与可见性
    Java 并发理论简述
    Java读取Properties文件的六种方法
    Java中的注解是如何工作的?
    XML解析——Java中XML的四种解析方式
  • 原文地址:https://www.cnblogs.com/starseven/p/13562008.html
Copyright © 2011-2022 走看看