• GDCPC2021 B


    题目

    source

    题解

    方法一:
    可以知道,最多35位Fibonacci数列就可以表示1e7的数。可以发现,前23位表示的数存在大量重复。因此可以先预处理出前23位的结果,然后剩下12位和预处理结果暴力卷积。前23位预处理最大的数为75024,剩下4096的需要处理,故最多计算75024*4096=2e8。不过一遍到不了那么大,因此能过。

    #include<iostream>
    using namespace std;
    const int N = 1e7 + 10;
    const int M = 998244353;
    typedef long long ll;
    int mx;
    int f[40];
    int ans[N];
    int ans2[N];
    int s, mxv;
    void dfs(int p, int val, int res) {
        if(p >= mx) {
            mxv = max(mxv, val);
            ans[val] += res;
            ans[val] %= M;
            return ;
        }
        dfs(p + 1, val, res);
        dfs(p + 1, val + f[p], 1ll * res * f[p] % M);
         
    }
     
    void solve(int p, int val, int res) {
        if(val >= N) return ;
        if(p >= 35) {
            if(val)
                for(int i = 0; i <= mxv && val + i < N; i++) {
                    ans2[val + i] += 1ll * ans[i] * res % M;
                    ans2[val + i] %= M;
                }
            return ;
        }
        solve(p + 1, val, res);
        solve(p + 1, val + f[p], 1ll * res * f[p] % M);
         
    }
     
    int main() {
        f[0] = 1;
        f[1] = 1;
        for(int i = 2; i < 40; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        mx = 23;
        dfs(0, 0, 1);
        solve(mx, 0, 1);
        int t;
        scanf("%d", &t);
        while(t--) {
            int n;
            scanf("%d", &n);
            printf("%d
    ", (ans[n] + ans2[n]) % M);
        }
    }
    

    方法二:
    Fibonacci数列前缀和为(g(n)=f(n+2)-1)。设小于等于n的最大的两个项为(f_{0n})(f_{1n}),那么n只能包含这两者中的一个。因此可以设(dp_{0n})(dp_{1n})为选择两者中一个的答案,这样直接dp可以计算。注意选择的冲突处理,详见代码。

    #include<iostream>
    using namespace std;
    const int N = 1e7 + 10;
    const int M = 998244353;
    typedef long long ll;
    
    int dp[2][N];
    int f[40];
    
    int main() {
    	f[0] = f[1] = 1;
    	dp[0][0] = 1;
    	dp[0][1] = 1;
    	dp[1][1] = 1;
    	for(int i = 2; i < 40; i++) f[i] = f[i - 1] + f[i - 2];
    	int cur = 0;
    	for(int i = 2; i < N; i++) {
    		if(i >= f[cur]) {
    			while(i >= f[cur]) cur++;
    			cur--;
    		}
    		int v1 = f[cur], v2 = f[cur - 1];
    		dp[0][i] = 1ll * (dp[0][i - v1] + dp[1][i - v1]) * v1 % M;
    		if(i - v2 < v2) // i-v2已经包含位置cur,故i不能选cur
    			dp[1][i] = 1ll * (dp[0][i - v2] + dp[1][i - v2]) * v2 % M;
    		else 
    			dp[1][i] = 1ll * (dp[1][i - v2]) * v2 % M;
    	}
    	int t;
    	scanf("%d", &t);
    	while(t--) {
    		int n;
    		scanf("%d", &n);
    		printf("%d
    ", (dp[0][n] + dp[1][n]) % M);
    	}
    }
    
  • 相关阅读:
    windows下配置docker
    libxml2 安装及使用
    lua 5.3 英文手册 自己收集整理版
    Unity3D RPC调用顺序问题
    对于问题的一个思考
    第十三章博客
    第十一章
    第十章博客
    第九章笔记
    S1304数据库前三章测试错题
  • 原文地址:https://www.cnblogs.com/limil/p/14973631.html
Copyright © 2020-2023  润新知