蓝桥杯刷题五

1.01背包问题

这题就是01背包问题的模板题 回顾一下01背包 01就是这个东西选和不选

01背包的表达式是f[i]=max(f[i-v]+w,f[i]);

那么这题就可以直接做了 值得注意的是这里只用了一维数组 所以更新的时候要从后往前面更新

#include 
using namespace std;
const int N=1e3+10;
int f[N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i>v>>w;
        for(int j=m;j>=v;j--)
        {
            f[j]=max(f[j],f[j-v]+w);
        }
    }
    cout<

2.摘花生

这题是简单的线性dp,分析一下假定起点为f[1][1],终点是f[n][m] 并且每次都只能东走或者往南走(这句话就是决定了本题没有任何的循环依赖),所以可以用dp做f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j]

#include 
using namespace std;
const int N=110;
int f[N][N];
int a[N][N];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(f,0,sizeof f);
        memset(a,0,sizeof a);
        int r,c;
        cin>>r>>c;
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                cin>>a[i][j];
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
                f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
        cout<

3.最长上升子序列

这也是很经典的线性dp。定义f[i]是以i为结尾的最长上升子序列,那我们去找在他前面的比它小的,并且去比较是f[i]大 还是f[j]+1 大 这样递归去求 就可以做了

注意 要把f[i]定义为1先 这是具体含义决定的

#include 

using namespace std;

const int N = 1010;

int res, a[N], f[N];

int main() {
    int n;  cin >> a[i];

    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }

    for (int i = 1; i <= n; i ++) {
        f[i] = 1;
        for (int j = 1; j < i; j ++) {
            if (a[i] > a[j]) {
                f[i] = max(f[i], f[j] + 1);
            }
        }

        res = max(res, f[i]);
    }

    return cout << res << '\n', 0;
}

4.地宫取宝

这个很像递归,

递归怎么递归呢

当走到某个格子上的时候:

(1)如果格子上宝贝的价值大于已有宝贝的最大值,那么可以选择拿或者不拿

(2)如果格子上宝贝的价值小于或者等于已有宝贝的最大值,那么只能选择不拿。

必须从左上角走到右下角,且只要到达右下角时物品个数满足条件即算一种方案。

只能选择向下或者向右走

不是必须到出口时,宝贝数量恰好满足条件,而是可以在任意位置就宝贝数量就可以满足条件,只需保证到达出口时宝贝数量仍然满足条件即可

#include 
using namespace std;
const int N=15;
int w[N][N];
int n,m;
int k;
int maxl=-0x3f3f3f3f;
const int mod=1000000007;
int dfs(int x,int y,int step,int Max)
{
    if(x>n||y>m||step>k) return 0;
    if(x==n&&y==m)
    {
        if(step==k||(w[x][y]>Max&&step+1==k))
            return 1;
        else return 0;
    }
    if(w[x][y]>Max)
    {
        return dfs(x,y+1,step+1,w[x][y])+
        dfs(x,y+1,step,Max)+
        dfs(x+1,y,step+1,w[x][y])+
        dfs(x+1,y,step,Max);
    }
    else return dfs(x,y+1,step,Max)+dfs(x+1,y,step,Max);
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>w[i][j];
    cout<

递归就超时了,所以要想别的办法 这题和摘花生有点像,那么应该是dp

那么就得用dp了 并且要用四维的dp去做x y step Max

由于宝贝的价值可以为0,因此一开始所持有0件宝贝,价值为-1,-1无法索引,为了便于在表中表示,我们将所有宝贝的价值都+1

蓝桥杯刷题五_第1张图片

递归改的代码在这里https://www.acwing.com/solution/content/34645/

蓝桥杯刷题五_第2张图片

初始化状态

蓝桥杯刷题五_第3张图片
#include 
#include 
#include 

using namespace std;

const int N = 55, MOD = 1000000007;

int n, m, k;
int w[N][N];
int f[N][N][13][14];

int main()
{
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            cin >> w[i][j];
            w[i][j] ++ ;
        }

    f[1][1][1][w[1][1]] = 1;
    f[1][1][0][0] = 1;

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            if (i == 1 && j == 1) continue;
            for (int u = 0; u <= k; u ++ )
                for (int v = 0; v <= 13; v ++ )
                {
                    int &val = f[i][j][u][v];
                    val = (val + f[i - 1][j][u][v]) % MOD;
                    val = (val + f[i][j - 1][u][v]) % MOD;
                    if (u > 0 && v == w[i][j])
                    {
                        for (int c = 0; c < v; c ++ )
                        {
                            val = (val + f[i - 1][j][u - 1][c]) % MOD;
                            val = (val + f[i][j - 1][u - 1][c]) % MOD;
                        }
                    }
                }
        }

    int res = 0;
    for (int i = 0; i <= 13; i ++ ) res = (res + f[n][m][k][i]) % MOD;

    cout << res << endl;

    return 0;
}

5.波动数列

设第一个数为 x, 第二个数为 x + d1, 第三个数为 x + d[1] + d[2]

第 n 个数为 x + d[1] + d[2] + ... + d[n - 1]; d[i] 的值为 a 或 -b

故数列之和 s = n * x + (n - 1) * d[1] + ... + (n - i) * d[i] + ... + d[n - 1]

x = (s - ((n - 1) * d[1] + ... + (n - i) * d[i] + ... + d[n - 1])) / n

因为 x 为任意整数, 故:

s % n == ((n - 1) * d[1] + ... + (n - i) * d[i] + ... + d[n - 1]) % n

蓝桥杯刷题五_第4张图片

f[0,0]=1

#include 

using namespace std;

const int N = 1010, MOD = 100000007;

int f[N][N];
int get(int x, int y) {  // 返回 x 除 y 的正余数 
    return (x % y + y) % y; 
}

int main() {
    int n, s, a, b;
    cin >> n >> s >> a >> b;

    f[0][0] = 1;
    for (int i = 1; i < n; i ++) {
        for (int j = 0; j < n; j ++) {
            int x = get(j - (n - i) * a, n);
            int y = get(j + (n - i) * b, n);
            f[i][j] = (f[i - 1][x] + f[i - 1][y]) % MOD;
        }
    }

    return cout << f[n - 1][get(s, n)] << '\n', 0;
}

你可能感兴趣的:(蓝桥杯,蓝桥杯,算法)