CF821 E. Okabe and El Psy Kongroo 矩阵快速幂

Posted ( m Lweleth)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF821 E. Okabe and El Psy Kongroo 矩阵快速幂相关的知识,希望对你有一定的参考价值。

LINK

题意:给出$n$条平行于x轴的线段,终点$k$坐标$(k <= 10^{18})$,现在可以在线段之间进行移动,但不能超出两条线段的y坐标所夹范围,问到达终点有几种方案。

思路:刚开始以为限制只是到达线段上就必须沿线段走,后来才发现是要求走y坐标所夹范围,那么就简单多了,很容易看出是个递推形DP,然而数据量有点大,k为10的18次,一般转移显然不可行。由于是个递推,而且y坐标最大也只有15,故使用矩阵优化递推复杂度即可。

 

/** @Date    : 2017-07-04 16:06:18
  * @FileName: E 矩阵快速幂 + 递推.cpp
  * @Platform: Windows
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;
const LL mod = 1e9 + 7;
int len;
LL n, k;
struct yuu
{
	LL mat[18][18];
	yuu(){MMF(mat);}
	void init()
	{
		for(int i = 0; i <= 17; i++)
			mat[i][i] = 1;
	}
	yuu operator *(const yuu &b)
	{
		yuu c;
		for(int i = 0; i <= len; i++)
		{
			for(int j = 0; j <= len; j++)
			{
				for(int k = 0; k <= len; k++)
				{
					c.mat[i][j] = (c.mat[i][j] + this->mat[i][k] * b.mat[k][j] % mod) % mod;
				}
			}
		}
		return c;
	}
};
yuu fpow(yuu a, LL n)
{
    yuu res;
    res.init();
	while(n)
	{
		if(n & 1)
			res = res * a;
		a = a * a;
		n >>= 1;
	}
    return res;
}

int main()
{
	while(cin >> n >> k)
	{
		yuu A, B, t;
		for(int i = 0; i < 16; i++)
		{
			int x = i - 1;
			if(x < 0)
				A.mat[i][x + 1] = 1;
			else A.mat[i][x] = 1;
			A.mat[i][x + 1] = A.mat[i][x + 2] = 1;
		}
		
		t.mat[0][0] = 1;
		int flag = 0;
		for(int i = 0; i < n; i++)
		{
			LL l, r, c;
			scanf("%lld%lld%lld", &l, &r, &c);
			if(flag)
				continue;
			flag = 0;
			r = min(r, k);
			if(r == k)
				flag = 1;
			len = c;
			B = fpow(A, r - l);
			for(int i = c + 1; i < 16; i++)
				t.mat[i][0] = 0;
			B = B * t;
			for(int i = 0; i <= len; i++)
				t.mat[i][0] = B.mat[i][0];
			
		}
		printf("%lld\n", B.mat[0][0]);
	}

    return 0;
}

以上是关于CF821 E. Okabe and El Psy Kongroo 矩阵快速幂的主要内容,如果未能解决你的问题,请参考以下文章

Codeforce821E Okabe and El Psy Kongroo

Codeforces 821E Okabe and El Psy Kongroo

CF821C Okabe and Boxes

CF821B Okabe and Banana Trees

CF821 A. Okabe and Future Gadget Laboratory 水

CF821 C. Okabe and Boxes 栈模拟