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 (SoungEarlf@gmail.com)
  * @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
", B.mat[0][0]);
	}

    return 0;
}
原文地址:https://www.cnblogs.com/Yumesenya/p/7189802.html