Codeforces Round 934 (Div. 2) ---- counting is fun (Easy and Hard Version)

目录

[F1. Counting Is Fun (Easy Version):](#F1. Counting Is Fun (Easy Version):)

题目大意:

思路解析:

代码实现:

[D2. Counting Is Fun (Hard Version):](#D2. Counting Is Fun (Hard Version):)

思路解析:

代码实现:


F1. Counting Is Fun (Easy Version):

题目大意:

思路解析:

我们可以考虑一下,在题目条件下好数组有什么性质。 假如n=4, 那我们令好数组的四个值为 a b c d。 假如我们第一次的选择 [l,r] == [1,2],那么数组值为 1 1 0 0,或者 k k 0 0.第二次选择[l,r] ==[2,3], 那么数组值为 k k+m m 0, 可以发现如果ai增加了f, 那么 ai-1 或者 ai+1 也一定会增加 f。所以可以发现一个特殊的性质 ai <= ai-1 + ai+1。 那么我们便可以利用这个性质来进行dp了。

dp[a][b] 代表在当前 位置i下,ai==b,ai == a的情况下满足好数组的定义的数组个数有多少。那么i+1转移 dp[b][c] = dp[m][b] (max(b-c, 0) <= m <= m ) 对m求和。 这里m的取值范围用到上诉发现的性质即可。 时间复杂度为 O(N^3)

代码实现:

复制代码
import java.io.*;
import java.math.BigInteger;
import java.util.*;
 
public class Main {
    static int inf = (int) 2e7;
 
    public static void main(String[] args) throws IOException {
        int t = f.nextInt();
        while (t > 0) {
            solve();
            t--;
        }
 
        w.flush();
        w.close();
        br.close();
    }
 
    public static void solve() {
        int n = f.nextInt(); int k = f.nextInt(); int mod = f.nextInt();
        int[][] dp = new int[k+1][k+1];
        dp[0][0] = 1;
        for (int i = 1; i <= n+2; i++) {
            int[][] ndp = new int[k+1][k+1];
            int[][] pre = new int[k+1][k+1];
            for (int b = 0; b <= k; b++) {
                pre[b][0] = dp[0][b];
                for (int a = 1; a <= k; a++) {
                    pre[b][a] = (pre[b][a-1] + dp[a][b]) % mod;
                }
            }
 
            for (int b = 0; b < k+1; b++) {
                for (int c = 0; c < k + 1; c++) {
                    if (b > c) ndp[b][c] = (pre[b][k] - pre[b][b-c-1] + mod) % mod;
                    else ndp[b][c] = pre[b][k];
                }
            }
            dp = ndp;
        }
        w.println(dp[0][0]);
    }
 
 
    static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
    static Input f = new Input(System.in);
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
    static class Input {
        public BufferedReader reader;
        public StringTokenizer tokenizer;
 
        public Input(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }
 
        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }
 
        public String nextLine() {
            String str = null;
            try {
                str = reader.readLine();
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            return str;
        }
 
        public int nextInt() {
            return Integer.parseInt(next());
        }
 
        public long nextLong() {
            return Long.parseLong(next());
        }
 
        public Double nextDouble() {
            return Double.parseDouble(next());
        }
 
        public BigInteger nextBigInteger() {
            return new BigInteger(next());
        }
    }
}

D2. Counting Is Fun (Hard Version):

思路解析:

题目大意类似,只是把n的限制范围 调到了 n <= 3000, 根据简单版本的时间复杂度O(N^3) 是过不了的,考虑怎么进行优化,第一题我们是枚举 b 和 c 通过特殊性质来推出a的可行范围,那我们想是否可以只枚举c,然后通过容斥原理来进行转移的加速。

第一个版本的枚举 :

a1 m c: -> a1 >=m-c ---- 相当于 ai-2等于这些数(0 ---- m-c-1) 是无效的

a2 m-1 c: -> a2 >= m-1-c ---- 相当于 ai-2等于这些数(0 ---- m-c-2) 是无效的

a3 m-2 c: -> a3 >= m-2-c ..... ---- 相当于 ai-2等于这些数(0 ---- m-c-3) 是无效的

那么便可以推出一个结论 :f(i,j) = f(i-1,k) - f(i-2,k) * (K - j - k) 对 k = (1,K)进行求和; 然后发现后面两个数组在 O(N)的情况下就可以使用前缀和预处理出来。

代码实现:

复制代码
import java.io.*;
import java.math.BigInteger;
import java.util.*;

public class Main {
    static int inf = (int) 2e7;

    public static void main(String[] args) throws IOException {
        int t = f.nextInt();
        while (t > 0) {
            solve();
            t--;
        }

        w.flush();
        w.close();
        br.close();
    }

    public static void solve() {
        int n = f.nextInt(); int k = f.nextInt(); int mod = f.nextInt();
        long[][] dp = new long[n+2][k+1];
        dp[0][0] = 1;
        for (int i = 1; i <= n + 1; i++) {
            long s = 0;
            for (int j = 0; j <= k; j++) {
                s += dp[i-1][j];
                s %= mod;
            }
            for (int j = 0; j <= k; j++) {
                dp[i][j] = s;
            }
            if (i >= 2){
                long[] g = new long[k+1];
                long[] h = new long[k+1];
                for (int j = 0; j <= k; j++) {
                    g[j] = dp[i - 2][j];
                    h[j] = dp[i-2][j] * j;
                    if (j > 0){
                        g[j] += g[j-1];
                        h[j] += h[j-1];
                        g[j] %= mod;
                        h[j] %= mod;
                    }
                }
                for (int j = 0; j <= k; j++) {
                    long x = (g[k - j] * (k - j) - h[k - j] + mod) % mod;
                    dp[i][j] = (dp[i][j] - x + mod) % mod;
                }
            }

        }
        w.println(dp[n+1][0]);
    }


    static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
    static Input f = new Input(System.in);
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class Input {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public Input(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public String nextLine() {
            String str = null;
            try {
                str = reader.readLine();
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            return str;
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public Double nextDouble() {
            return Double.parseDouble(next());
        }

        public BigInteger nextBigInteger() {
            return new BigInteger(next());
        }
    }
}
相关推荐
小龙报几秒前
《算法通关指南数据结构和算法篇(2)--- 链表专题》
c语言·数据结构·c++·算法·链表·学习方法·visual studio
艾莉丝努力练剑21 分钟前
【优选算法必刷100题】第031~32题(前缀和算法):连续数组、矩阵区域和
大数据·人工智能·线性代数·算法·矩阵·二维前缀和
醉颜凉22 分钟前
环形房屋如何 “安全劫舍”?动态规划解题逻辑与技巧
c语言·算法·动态规划
大雨淅淅26 分钟前
一文搞懂动态规划:从入门到精通
算法·动态规划
不去幼儿园28 分钟前
【启发式算法】灰狼优化算法(Grey Wolf Optimizer, GWO)详细介绍(Python)
人工智能·python·算法·机器学习·启发式算法
随意起个昵称29 分钟前
【二分】洛谷P2920,P2985做题小记
c++·算法
没书读了35 分钟前
计算机组成原理-考前记忆清单
线性代数·算法
Hcoco_me1 小时前
大模型面试题5:矩阵(M*M)特征值分解的步骤
算法·机器学习·矩阵
非著名架构师2 小时前
极端天气下的供应链韧性:制造企业如何构建气象风险防御体系
大数据·人工智能·算法·制造·疾风气象大模型·风光功率预测
星轨初途2 小时前
数据结构排序算法详解(2)——选择排序(附动图)
c语言·数据结构·经验分享·笔记·b树·算法·排序算法