• 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;
    }
    
  • 相关阅读:
    默认构造函数
    Android笔记(二十八) Android中图片之简单图片使用
    Android笔记(二十七) Android中的动态广播和静态广播
    Android笔记(二十六) Android中的广播——BroadcastReceiver
    <转> Android LayoutInflater详解
    Android笔记(二十五) ListView的缓存机制与BaseAdapter
    Android笔记(二十四) Android中的SeekBar(拖动条)
    Android笔记(二十三) Android中的ProgressBar(进度条)
    Android笔记(二十二) Android中的GridView
    Android笔记(二十一) Android中的Adapter
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/7189802.html
Copyright © 2020-2023  润新知