zoukankan      html  css  js  c++  java
  • bzoj2476 战场的数目 矩阵快速幂

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=2476

    题解

    想要做这道题还得去看一下上一道题的题面 2333

    首先满足题目要求的是凸的大方块,并且每一个方块的下面一定要有方块(或者位于底层);最后这个还不能是一个完整的矩形。

    我们先忽略最后一个条件。

    很容易发现,如果我们删掉最左边、最右边或者最上边的一行或者一列方块,周长都会恰好减少 (2)。可惜这个结论看起来用不上啊,因为还需要保证删掉以后的下一行或者下一列的方块数量不少于删掉的那一行或者那一列。

    考虑如何解决这个限制。为什么这个限制会有影响呢?如果被删掉的那一列只有一个方块,那么就没有这个影响了啊。所以我们考虑只删除最右边或者最左边的只有一个方块的那一列。

    那么最后会形成最下面两行的方块数相同的情况——这种情况也很好解决了,既然都相同了,删去最后一行也是周长恰好减少 (2)

    所以我们令 (f(i)) 表示周长为 (i) 的方块数量。

    那么我们有 (f(i) = 3f(i-1))。注意到最左边和最右边都有方块的情况会被算重。所以还需要减去 (f(i-2))。因此最终的递推是为 (f(i) = 3f(i-1)-f(i-2))

    用矩阵加速即可。

    最后把 (f(n)) 的结果在减去 (n-1)——这个是之前的最后一个条件的影响。


    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int P = 987654321;
    
    int n;
    
    inline int smod(int x) { return x >= P ? x - P : x; }
    inline void sadd(int &x, const int &y) { x += y; x >= P ? x -= P : x; }
    inline int fpow(int x, int y) {
    	int ans = 1;
    	for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
    	return ans;
    }
    
    struct Matrix {
    	int a[2][2];
    	
    	inline Matrix() { memset(a, 0, sizeof(a)); }
    	inline Matrix(const int &x) {
    		memset(a, 0, sizeof(a));
    		a[0][0] = a[1][1] = x;
    	}
    	
    	inline Matrix operator * (const Matrix &b) {
    		Matrix c;
    		c.a[0][0] = ((ll)a[0][0] * b.a[0][0] + (ll)a[0][1] * b.a[1][0]) % P;
    		c.a[0][1] = ((ll)a[0][0] * b.a[0][1] + (ll)a[0][1] * b.a[1][1]) % P;
    		c.a[1][0] = ((ll)a[1][0] * b.a[0][0] + (ll)a[1][1] * b.a[1][0]) % P;
    		c.a[1][1] = ((ll)a[1][0] * b.a[0][1] + (ll)a[1][1] * b.a[1][1]) % P;
    		return c;
    	}
    } A, B;
    
    inline Matrix fpow(Matrix x, int y) {
    	Matrix ans(1);
    	for (; y; y >>= 1, x = x * x) if (y & 1) ans = ans * x;
    	return ans;
    }
    
    inline void work() {
    	if (n & 1) return (void)puts("0");
    	n >>= 1;
    	if (n == 1) return (void)puts("0");
    	if (n == 2) return (void)puts("1");
    	if (n == 3) return (void)puts("2");
    	B.a[0][0] = 2, B.a[1][0] = 1;
    	A.a[0][0] = 3, A.a[0][1] = -1;
    	A.a[1][0] = 1, A.a[1][1] = 0;
    	B = fpow(A, n - 3) * B;
    	int ans = smod(B.a[0][0] - n + 1 + P);
    	printf("%d
    ", ans);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	while (read(n), n) work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    用 Timer Applet 做 GTD 料理
    Envy-便当的显卡驱动布置剧本
    DB2 9 运用开发(733 测验)认证指南,第 1 部分: 数据库工具与编程办法(1)
    Sabayon:经管 GNOME 用户的设置
    应用 KScope 阅读并编纂你的源代码
    Cheese-从摄像头捕捉照片和视频
    Kaffeine Player:功用富厚的媒体播放器
    SpeedCrunch:很酷的桌面较量争论器
    DB2 9 根蒂根基(730 测验)认证指南,第 7 部分: XQuery 简介(6)
    Conduit 0.3.2 颁布
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj2476.html
Copyright © 2011-2022 走看看