2020蓝桥杯模拟赛

第九题 序列计数
题目
【问题描述】
小明想知道,满足以下条件的正整数序列的数量:
1. 第一项为 n;
2. 第二项不超过 n;
3. 从第三项开始,每一项小于前两项的差的绝对值。
请计算,对于给定的 n,有多少种满足条件的序列。
【输入格式】
输入一行包含一个整数 n。
【输出格式】
输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。
【样例输入】
4
【样例输出】
7
【样例说明】
以下是满足条件的序列:
4 1
4 1 1
4 1 2
4 2
4 2 1
4 3
4 4
【评测用例规模与约定】
对于 20% 的评测用例,1 <= n <= 5;
对于 50% 的评测用例,1 <= n <= 10;
对于 80% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 1000。

暴力显然超时,选择记忆化

#include<bits/stdc++.h>
#define mod 10000 
using namespace std;
int n, ans = 0, cha, vis[1005][1005], pass; 
void dfs(int up, int x){
    ans += x - 1;
    ans %= mod;
    int k = ans;
    for(int i = x - 1; i > 0; i--){
        cha = abs(up - i);
        if(vis[up][i]){
            ans = (ans + vis[up][i]) % mod;
            k = ans;
            continue;
        }
        else if(cha){
            dfs(i, cha);
            vis[up][i] = (ans - k + mod) % mod;
            k = ans;
        }
    }
}
int main(){
    cin >> n;
    ans += n;
    for(int i = n; i >= 1; i--){
        cha = n - i;
        pass = ans;
        if(cha){
            dfs(i, cha);
            vis[n][i] = (ans - pass + mod) % mod;
        }
    }
    cout << ans;
}
View Code

然而单纯加入记忆化只能保证过80%的点,所以需要进一步优化。

如果我们用f(i,j)表示前一个数是i,当前数是1到j的合法序列的个数;有f(i,j) = 1 + f(i,j-1) + f(j,abs(i-j)-1)即分为两个部分1)i作为前一个数,从1到j-1为当前数的合法序列的个数已经计算好,2)求以j为尾数,后面选择1到abs(i-j)-1的合法序列的个数。

之前是从1到j循环加,现在一步到位,时间复杂度大大降低。

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
const int mod = 10000;
int n, vis[1005][1005];
int dfs(int pre, int cur){
    if(cur <= 0) return 0;
    if(vis[pre][cur]) return vis[pre][cur];
    return vis[pre][cur] = (1 + dfs(pre, cur - 1) + dfs(cur, abs(pre - cur) - 1)) % mod;
}
int main(){
    cin >> n;
    cout << dfs(n, n) << "\n";
    return 0;
}
View Code

 

第十题 晚会节目单
题目
【问题描述】
小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
【输入格式】
输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。
第二行包含 n 个整数,依次为每个节目的好看值。
【输出格式】
输出一行包含 m 个整数,为选出的节目的好看值。
【样例输入】
5 3
3 1 2 5 4
【样例输出】
3 5 4
【样例说明】
选择了第1, 4, 5个节目。
【评测用例规模与约定】
对于 30% 的评测用例,1 <= n <= 20;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。

此题关键在于“第一个节目尽可能好看”并希望“第二个节目尽可能好看”……那么我们选择的第一节目就是max(g[1]~g[n-m+1])闭区间,要选择的第二个节目是max(g[lastMax+1],g[n-m+2])即从上一个节目往下到n-m+2这个区间里面选最好看的,直到剩下的必须全部选择。

自己拿ST写的,不知道有没有问题- -

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
const int maxn = 100005;
int n, m, f[maxn][22], ans[maxn], cnt[maxn][22], now = 1;
int query(int l, int r){
    int k = log2(r - l + 1);
    if(f[l][k] >= f[r - (1 << k) + 1][k]){
        now = cnt[l][k];
        return f[l][k];
    }
    else{
        now = cnt[r - (1 << k) + 1][k];
        return f[r - (1 << k) + 1][k];
    }
}
int main(){
    n = read(), m = read();
    for(ri i = 1; i <= n; ++i){
        f[i][0] = read();
        cnt[i][0] = f[i][0];
    }
        
    for(ri j = 1; j <= 21; ++j)
        for(ri i = 1; i + (1 << j) <= n + 1; ++i){
            if(f[i][j - 1] >= f[i + (1 << (j - 1))][j - 1]){
                f[i][j] = f[i][j - 1];
                cnt[i][j] = cnt[i][j - 1];
            }
            else{
                f[i][j] = f[i + (1 << (j - 1))][j - 1];
                cnt[i][j] = cnt[i + (1 << (j - 1))][j - 1];
            }
        }
    for(ri i = m; i >= 1; --i)
        printf("%d ", query(now, n - i + 1));
    printf("\n");
    return 0;
}
View Code

 

posted @ 2020-03-26 09:03  kojoker  阅读(515)  评论(0)    收藏  举报