zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    evernote100个做笔记的好方法
    平衡二叉树的调整模版
    晨间日记的奇迹
    hdu 2952 Counting Sheep
    hdu 1535 Invitation Cards
    poj 3259 Wormholes(spfa)
    poj 2263 Heavy Cargo(floyd)
    poj 3268 Silver Cow Party(SPFA)
    hdu 1690 Bus System
    hdu 3631 Shortest Path(Floyd)
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/7189802.html
Copyright © 2011-2022 走看看