• 洛谷 P4910 帕秋莉的手环


    题意

    多组数据,给出一个环,要求不能有连续的(1),求出满足条件的方案数

    (1le T le 10, 1le n le 10^{18})

    思路

    20pts

    暴力枚举(不会写

    60pts

    假设金珠子为(0),木珠子为(1),则不能有连续的木珠子

    线性递推(DP),设(f[i][0/1])表示当前填到第(i)位,第(i)位为金珠子/木珠子的方案数,那么有:

    [f[i][0] = f[i - 1][0] + f[i - 1][1] ]

    [f[i][1] = f[i-1][0] ]

    但是要分成两种情况讨论

    • 第一个位置是(0),则(f[1][0]=1,f[1][1]=0),那么最后一个位置可以是(0)也可以是(1)

      所以此时对答案的贡献为(f[n][0]+f[n][1])

    • 第一个位置是(1),则(f[1][1]=1,f[1][0]=0),那么最后一个位置只能是(0)

      所以此时对答案的贡献为(f[n][0])

    时间复杂度(O(Tn)),期望得分(60)

    不知道为什么,也许是我写假了,只有48分

    100pts

    考虑用矩阵优化,目前的状态为([f_{i,0},f_{i,1}]),目标状态为([f_{i+1,0},f_{i+1,1}]),比较容易推出转移矩阵为

    [[f_{i,0},f_{i,1}] * left[ egin{matrix} 1 & 1 \ 1 & 0 end{matrix} ight] = [f_{i+1,0},f_{i+1,1}] ]

    按照(60)分做法写矩阵快速幂就好了

    代码

    60pts

    /*
    Author:loceaner
    假设不能有连续的1 
    用f[i][0/1]表示选到了i处,第i处为白/黑的方案数
    f[i][1] = f[i - 1][0]
    f[i][0] = f[i - 1][1] + f[i - 1][0]
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 1e6 + 10000;
    const int B = 1e6 + 11;
    const int mod = 1000000007;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
    	char c = getchar(); int x = 0, f = 1;
    	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    	return x * f;
    }
    
    int n, f[A][2];
    
    int main() {
    	int T = read();
    	while(T--) {
    		n = read();
    		long long ans = 0;
    		f[1][0] = 1, f[1][1] = 0;
    		for (int i = 2; i <= n; i++) {
    			f[i][1] = f[i - 1][0] % mod;
    			f[i][0] = (f[i - 1][1] + f[i - 1][0]) % mod;
    		} 
    		ans = (f[n][0] + f[n][1]) % mod; 
    		f[1][0] = 0, f[1][1] = 1;
    		for (int i = 2; i <= n; i++) {
    			f[i][1] = f[i - 1][0] % mod;
    			f[i][0] = (f[i - 1][1] + f[i - 1][0]) % mod;
    		} 
    		(ans += f[n][0]) %= mod;
    		cout << ans << '
    ';
    	}
    	return 0;
    }
    

    100pts

    /*
    Author:loceaner
    */
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define int long long
    using namespace std;
    
    const int A = 1e6 + 10000;
    const int B = 1e6 + 11;
    const int mod = 1000000007;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
    	char c = getchar(); int x = 0, f = 1;
    	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    	return x * f;
    }
    
    int n;
    
    struct mat { int a[2][2]; } a, b, c;
    
    mat operator * (const mat &a, const mat &b) {
    	mat c;
    	memset(c.a, 0, sizeof(c.a));
    	for (int k = 0; k <= 1; k++) 
    		for (int i = 0; i <= 1; i++)
    			for (int j = 0; j <= 1; j++)
    				c.a[i][j] = (c.a[i][j] + a.a[i][k] % mod * b.a[k][j] % mod) % mod;
    	return c;
    }
    
    mat ksm(mat a, int b) {
    	mat ans;
    	memset(ans.a, 0, sizeof(ans.a));
    	for (int i = 0; i <= 1; i++) ans.a[i][i] = 1;
    	while (b) {
    		if (b & 1) ans = ans * a;
    		a = a * a, b >>= 1;
    	}
    	return ans;
    }
    
    signed main() {
    	int T = read();
    	while(T--) {
    		n = read();
    		int ans = 0;
    		memset(a.a, 0, sizeof(a.a));
    		a.a[0][0] = a.a[0][1] = a.a[1][0] = 1;
    		a = ksm(a, n - 1);
    		memset(b.a, 0, sizeof(b.a));
    		b.a[0][0] = 1, b = b * a;
    		ans = (ans + b.a[0][0] % mod + b.a[0][1]) % mod;
    		memset(c.a, 0, sizeof(c.a));
    		c.a[0][1] = 1, c = c * a;
    		ans = (ans + c.a[0][0]) % mod;
    		cout << ans << '
    ';
    	}
    }
    
  • 相关阅读:
    HeadFirst设计模式C++实现-AbstractFactory模式
    Head First设计模式C++实现Singleton模式
    系统程序员成长计划动态数组(三)(上)
    一种OPENSSL_Uplink(100F2010,05): no OPENSSL_Applink解决方法
    系统程序员成长计划动态数组(四)
    Head First设计模式C++实现Command模式
    EJB>事务管理服务 小强斋
    EJB>事务管理服务 小强斋
    EJB>实体继承 小强斋
    EJB>事务管理服务 小强斋
  • 原文地址:https://www.cnblogs.com/loceaner/p/13155604.html
Copyright © 2020-2023  润新知