zoukankan      html  css  js  c++  java
  • dp cf 1700 最近几天的刷题

    C. Number of Ways

    这个题目的意思是,把这个n的序列分成三个连续的部分,要求这三个部分的和是一样的。问这种划分的方法有多少种。

    这个题目和之前写过的数字划分有点像,这个就是要先进行前缀和的处理,然后找到s/3 和 2*s/3 这两个位置。

    因为这个有负数,所以有可能出现,2*s/3 的位置在 s/3 的位置之后,所以这个时候就需要进行处理。

    我们每一个 s/3 去找到 2*s/3 的所有合法位置即可。

    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 5e5 + 10;
    ll a[maxn], sum[maxn];
    int x[maxn], y[maxn];
    
    int main()
    {
        int n;
        ll S = 0;
        scanf("%d", &n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld", &a[i]);
            sum[i] = sum[i - 1] + a[i];
            S += a[i];
        }
        if (S % 3 != 0) {
            printf("0
    ");
            return 0;
        }
        S /= 3;
        int tot = 0, cnt = 0;
        for(int i=1;i<n;i++)
        {
            if (sum[i] == S) x[tot++] = i;
            if (sum[i] == 2 * S) y[cnt++] = i;
        }
        if(tot==0||cnt==0)
        {
            printf("0
    ");
            return 0;
        }
        ll ans = 0;
        for(int i=0;i<tot;i++)
        {
            ll len = upper_bound(y, y + cnt, x[i]) - y;
            ans += (cnt - len);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    C

    D. Flowers

    这个题目是一个很简单的线性dp。

    题目大意:土拨鼠吃花,对于白花,它只吃数量恰好为k这么多的白花,不然就不吃,它给你一个区间从a到b,表示花的数量从a到b,求土拨鼠吃花的方案数。

    这个和之前寒假回来后的选拔赛的dp是一样的,因为这个和顺序也有关,所以要先枚举背包容量,然后再去枚举种类,如果和放入背包的顺序无关,就是先枚举种类再去枚举数量。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define inf 0x3f3ff3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 10;
    const ll mod = 1e9 + 7;
    ll dp[maxn];
    ll sum[maxn];
    
    int main()
    {
        int t, k;
        scanf("%d%d", &t, &k);
        dp[0] = 1;
        for (int i = 1; i <= maxn; i++) {
            if (i >= k) {
                dp[i] = dp[i - 1] + dp[i - k];
                dp[i] %= mod;
            }
            else {
                dp[i] = dp[i - 1];
                dp[i] %= mod;
            }
        }
        for(int i=1;i<=maxn;i++)
        {
            sum[i] = sum[i - 1] + dp[i];
            sum[i] %= mod;
        }
        while(t--)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            ll ans = (sum[b] - sum[a - 1] + mod) % mod;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    D

    A. DZY Loves Sequences

    题目大意:您的任务是找到a的最长子段,这样可以从子段中最多更改一个数字(将一个数字更改为您想要的任何整数),以使子段严格增加。

    这个就是处理一下 对于第 i 个值,求出以 i 为起点的递增序列的长度,以 i 为终点的递增序列长度。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define inf 0x3f3ff3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 10;
    ll a[maxn], dp1[maxn], dp2[maxn];
    
    int main()
    {
        int n;
        scanf("%d", &n);
        a[0] = -inf;
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            dp1[i] = 1;
            dp2[i] = 1;
        }
        ll mx = 0;
        for (int i = 2; i <= n; i++) {
            if (a[i] > a[i - 1]) dp1[i] = dp1[i - 1] + 1;
            mx = max(dp1[i], mx);
        }
        for (int i = n - 1; i >= 1; i--) {
            if (a[i] < a[i + 1]) dp2[i] = dp2[i + 1] + 1;
            //printf("dp2[%d]=%lld
    ", i, dp2[i]);
        }
        ll ans = 1;
        for(int i=1;i<=n;i++)
        {
            if (a[i - 1] <= a[i + 1] - 2) ans = max(ans, dp1[i - 1] + dp2[i + 1] + 1);
        }
        if (mx < n) mx++;
        ans = max(ans, mx);
        printf("%lld
    ", ans);
        return 0;
    }
    A

    C. George and Job

    这个题目我觉得有点难,就是找到一个长度恰好为m的k个区间,然后这k个区间求和,使得和最大。

    这个n,m,k都比较小,所以可以定义一个二维的,这个和之前的奶牛的题目有点类似 https://www.cnblogs.com/EchoZQN/p/11043552.html

    这个是lj给了我这个dp状态的定义,我才写出来转移方程的 

    dp[i][j] 表示前面 i 个数,选了j个区间的最大和。

    所以这个转移方程就是 如果我们选了第i个数 那么  dp[i][j]=max(dp[i-m][j-1],dp[i][j])

    如果我们不选第 i 个数 那么 dp[i][j]=max(dp[i][j],dp[i-1][j])

    这个都写出来了,就很好写了。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define inf 0x3f3ff3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 10;
    ll sum[maxn], a[maxn], dp[5005][5005];
    
    int main()
    {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=k;j++)
            {
                if (i >= m) {
                    dp[i][j] = max(dp[i - m][j - 1] + sum[i] - sum[i - m], dp[i][j]);
                    dp[i][j] = max(dp[i - 1][j], dp[i][j]);
                }
                else dp[i][j] = dp[i - 1][j];
            }
        }
        printf("%lld
    ", dp[n][k]);
        return 0;
    }
    C

    B. Color the Fence

    这个题目不是很难,但是需要想一想。

    首先,我们优先考虑这个数的长度,然后再考虑这个数的大小。

    所以我们可以先由这个最小的数求出长度,然后再去找这个长度如果不整除,那就尽量选更大的。

    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 10;
    int b[maxn];
    int a[15];
    
    int main()
    {
        int V;
        scanf("%d", &V);
        int mn = inf;
        for (int i = 1; i <= 9; i++) {
            scanf("%d", &a[i]);
            mn = min(mn, a[i]);
        }
        if (V < mn) {
            printf("-1
    ");
            return 0;
        }
        //printf("mn=%d
    ", mn);
        int tot = 0;
        int len = V / mn;
        int M = V % mn;
        int mx = mn + M;
        while(len--)
        {
            //printf("len=%d mx=%d
    ", len, mx);
            int flag = 0;
            for(int i=9;i>=1;i--)
            {
                if(a[i]<=mx)
                {
                    flag = i;
                    b[tot++] = i;
                    break;
                }
            }
            mx -= (a[flag] - mn);
        }
        for (int i = 0; i < tot; i++) printf("%d", b[i]);
        printf("
    ");
        return 0;
    }
    B
  • 相关阅读:
    括号序列
    单向TSP
    Black Box
    震惊!!!某初中生竟30min一蓝两紫一黑!!!
    荷马史诗
    SUFEQPRE
    UVA劲歌金曲
    UVA城市里的间谍
    饼图----插件
    折线图-----插件
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11083275.html
Copyright © 2011-2022 走看看