• 小智的糖果(Candy) 51nod 提高组试题


    luogu AC通道! (官方数据)

    题目描述

    小智家里来了很多的朋友,总共有N个人,站成一排,分别编号为0到N-1,小智要给他们分糖果。但 是有的朋友有一些特殊的要求,有的人要求他左右的两个人(左边一个、右边一个,一共2个人)的 糖果数都比他的多,有的人要求他左右的两个人的糖果数都比他的少。同时小智希望给不同的人分到 的糖果数不相同,并且每个人至少有一个糖果,同时小智希望分出的糖果个数尽可能的少,现在小智 想知道有多少种分糖果的方法。数据保证不会出现两个人的要求产生冲突的情况。

    输入格式

    第一行三个数N,M,K,分别表示人数,第一种要求的人的个数,K表示第二种要求的人的个数。 接下来M行,每行一个数x,表示位置x的人要求他左右两个人的糖果数都比他的多 接下来K行,每行一个数y,表示位置y的人要求他左右两个人的糖果数都比他的少

    输出格式

    输出一个数表示方法数对 1000000007取模的结果。

    这道题考虑Dp解法。

    如何想到用DP解法?  因为题目中要求我们最多有多少种方法,如果一个个枚举或者求出的话,就会让我们的时间复杂度分分钟上去。因此这类题都是套路一般的DP。

    首先,看到题目中有两种要求。一种是让两边的小,一种是让两边的大。

    这种要求有一点不好处理的就是,我们总是喜欢直接查看每一个点的情况,而不是查看其旁边的点情况,这样很不方便。于是我们转换一下。

    设flagi = 1时,表示第 i 个点小于前一个点。同样的,当 flagi = 2时,表示第i个点大于前一个点。当然,falg = 0时,表示无特殊关系。

    然后,设置一个dp[i][j] 表示由前 i 个数组成的序列且第 i 位为 j 的合法情况数。在规划的过程中,针对不同的 flag[i],对应不同的状态转移,这里涉及到一个最后一位数 j 插入序列的思维,可以看做把前边的每一种排列中大于等于 j 的数 ++,也就可以达到空出 j 这个数将其插入的效果。

    在这里引入一个 sum[j],表示为前一轮状态下,最后一位小于等于 j 的情况的和。也就是说,当规划到第 i 位时,sum[j] 表示前 i - 1 位数组成的序列的合法情况的 dp[i - 1][j] 的前缀和。

    到这里,这道题也就可以被我们AC了。我们要求的和就是 sum[n].

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define N 100100
    #define isdigit(c) ((c)>='0'&&(c)<='9')
    const int mod = (int)1e9 + 7;
    
    inline int read(){
        int x = 0, s = 1;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-')s = -1;
            c = getchar();
        }
        while(isdigit(c)){
            x = (x << 1) + (x << 3) + (c ^ '0');
            c = getchar();
        }
        return x * s;
    }
    
    int flag[N], sum[N], dp[N];
    int main(){
    //    freopen("candy.in","r",stdin);
    //    freopen("candy.out","w",stdout);
        int n = read(), K = read(), M = read();
        for(int i = 1;i <= K; i++){
            int a = read();
            flag[++a] = 1;
            flag[a + 1] = 2;
        }
        for(int i = 1;i <= M; i++){
            int a = read();
            flag[++a] = 2;
            flag[a + 1] = 1;
        }
        dp[1] = sum[1] = 1;
        for(int i = 2;i <= n; i++){
            for(int j = 1;j <= i; j++){
                if(flag[i] == 0){
                    dp[j] = sum[i - 1] % mod;
                }
                else if(flag[i] == 1){
                    dp[j] = (sum[i - 1] - sum[j - 1] + mod) % mod;
                }
                else{
                    dp[j] = sum[j - 1];
                }
            }
            for(int j = 1;j <= i; j++){
                sum[j] = (sum[j - 1] + dp[j]) % mod;
            }
        }
        cout << sum[n] << endl;
        return 0;
    }
  • 相关阅读:
    oracle数据库的隔离级别MS
    常用的oracle数据备份恢复方法有哪些?每一种的应用场景是什么?如果我的数据库是1T,说说你的备份 规划方案MS
    oracle中不能把字段类型改为clob,blob
    oracle dataguard中的常用视图(DG中常用视图)
    导出oracle awr 报告的操作
    mysql 部分命令
    企业微信HOOK逆向(sdk)——登录二维码api
    学习 游泳
    Celery Bo7
    算法时间复杂度
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12896710.html
Copyright © 2020-2023  润新知