Atcoder 161 (A~E)

本文解析了五道经典编程题目,包括模拟操作、物品选择、数值处理、特殊数生成及工作日安排,提供了完整的题解思路与AC代码,涵盖了算法、数据结构、字符串处理等核心内容。

A
A题链接
根据题意模拟即可
AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>

typedef long long ll;
using namespace std;

int main()
{
    int a,b,c;
    cin>>a>>b>>c;
    cout<<c<<" "<<a<<" "<<b<<endl;
    return 0;
}

B
B题链接
题意:N个物品,每个都有一个权值,询问是否存在M个物品,其中每个物品的权值不小于权值和1/4m

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>

typedef long long ll;
using namespace std;

int main()
{
    int a[50000];
    int n,m;
    double sum=0;
    int k=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    sum=sum/(4*m);
    for(int i=1;i<=n;i++)
    {
        if(a[i]>=sum)
        {
            k++;
        }
    }
    if(k>=m)
    {
        cout<<"Yes";
    }
    else
    {
        cout<<"No";
    }
    return 0;
}

C
C题链接
题意:给你N和K,每次可以把N替换为N和K差的绝对值,询问所有替换中N的最小值
模拟即可
AC代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>

typedef long long ll;
using namespace std;

int main()
{
    ll a,b;
    cin>>a>>b;
    ll c=a%b;
    if(c==0)
    {
        cout<<0<<endl;
        return 0;
    }
    else
    {
        ll x=b-c;
        ll mins=min(x,c);
        cout<<mins<<endl;
    }
    return 0;
}

D
D题链接
题意:lunlun数的定义是该数字每一位与相邻位差的绝对值小于等于1,求第k小的lunlun数
题解:1~9入队列,然后进行判断如果大于0则末尾减一入队,如果小于9则可以加一入队列。
AC代码:

#include<iostream>
#include<cstdio>
#include <stdio.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include <set>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define inf 0x3f3f3f3f
using namespace std;
queue<ll> q;
int n;
int main()
{

    cin>>n;
    for(int i=1;i<=9;i++)
    {
        q.push(i);
    }
    for(int i=1;i<=n;i++)
    {

        ll pre=q.front();
        q.pop();
        if(i==n)
        {
            cout<<pre<<endl;
        }
        ll r=pre%10;
        pre=pre*10+r;
        if(r>0)
            q.push(pre-1);
        q.push(pre);
        if(r<9)
        {
            q.push(pre+1);
        }
    }

    return 0;
}

E
E题链接
题意: 给定一个字符串表示某人的工作日和休息日。只有在工作日才能工作,每次工作一天后的ccc天不能再工作。他一共要工作kkk天,问哪些天是必须工作的。
题解:先从前往后求出K个最快工作日,再从后往前求出K个最快工作日,
如果两边都参与的即为必须要做的
AC代码:

#include<iostream>
#include<cstdio>
#include <stdio.h>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#include <set>
#define ll long long
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#define inf 0x3f3f3f3f
using namespace std;
int a[200020];
int b[200020];
char c[200020];
int n,k,c1;
int main()
{
    int p=0,q=0;
    int temp=99999999;
    cin>>n>>k>>c1;
    cin>>c;
    for(int i=0; i<n; i++)
    {
        if(p==k)
        {
            break;
        }
        if(c[i]=='o'&&temp>=c1)
        {
            a[p++]=i;
            temp=0;
        }
        else
        {
            temp++;
        }

    }
    temp=99999999;
    q=k-1;
    for(int i=n-1; i>=0; i--)
    {
        if(q<0)
        {
            break;
        }
        if(c[i]=='o'&&temp>=c1)
        {
            b[q--]=i;
            temp=0;
        }
        else
        {
            temp++;
        }
    }
    for(int i=0;i<k;i++)
    {
        if(a[i]==b[i])
        {
            cout<<a[i]+1<<endl;
        }
    }
    return 0;
}

<think>首先,用户的问题是:“我想查找AtCoder平台上dp_e相关的信息,可能是题目解析、解题思路等 请问AtCoder dp_e题目解析及解题思路”。所以,我需要提供关于AtCoder的dp_e题目的解析和解题思路。 从系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如:[^1] 用户提供的引用内容: - 引用[1]:关于AtCoder入门建议。 - 引用[2]:关于动态规划的介绍。 - 引用[3]:关于动态规划的面试准备。 - 引用[4]:关于使用位运算优化DP的示例代码,特别是旅行商问题的代码。 用户提到了“dp_e”,这很可能指的是AtCoder上的一个问题编号。AtCoder有一个著名的动态规划(DP)系列问题,称为“Educational DP Contest”,其中问题编号如“dp_a”、“dp_b”等。dp_e应该是其中一个问题。 回想一下,AtCoder的Educational DP Contest有26个问题对应字母a到z。dp_e通常是“Knapsack 1”或背包问题的变种。具体来说: - dp_a: Coin Change - dp_b: Frog 1 - dp_c: Vacation - dp_d: Knapsack 1 (0/1 Knapsack with small constraints) - dp_e: Knapsack 2 (0/1 Knapsack with large weights) 在标准Educational DP Contest中: - dp_d是Knapsack 1,约束较小(W <= 10^5, N <= 100) - dp_e是Knapsack 2,约束较大(W <= 10^9, N <= 100),但价值较小,所以需要优化为基于价值的DP。 用户指定了“dp_e”,所以我需要提供dp_e的解析。 dp_e的题目是Knapsack 2: - 给定物品的重量和价值,以及背包容量,求最大价值。 - 约束:N(物品数) <= 100, W(背包容量) <= 10^9, 价值 <= 10^3。 - 由于W很大,不能直接用基于重量的DP(因为DP数组大小为W),需要改用基于价值的DP,因为总价值较小(最大100 * 1000 = 100,000)。 解题思路: 1. **问题分析**:标准0/1背包问题,但由于背包容量很大,直接使用O(NW)的DP会超出内存和时间限制。需要优化。 2. **优化策略**:既然价值较小(最多100,000),可以定义DP[i][v]为考虑前i个物品时,达到价值v所需的最小重量。 3. **状态转移方程**: - DP[i][v] = min(DP[i-1][v], DP[i-1][v - value[i]] + weight[i]) for v >= value[i] - 初始状态:DP[0][0] = 0, DP[0][v] = infinity for v > 0 4. **实现**:使用二维DP数组,优化空间复杂度到一维。 5. **最终答案**:找到最大的v,使得DP[N][v] <= W。 参考用户提供的引用: - 引用[4]中有一个位运算优化DP的示例,但那是针对旅行商问题的,不直接适用于背包问题。但可以提及DP优化的一般思想。 - 引用[2]和[3]讨论动态规划的基础,可以作为背景。 在回答中,需要自然地引用这些内容。例如,提到动态规划概念时,引用[2]:“动态规划是一种解决复杂问题的强大技术[^2]”。 回答结构: - 引言:介绍dp_e题目。 - 题目描述:简述问题。 - 解题思路:详细步骤。 - 代码示例:提供伪代码或Python代码。 - 生成相关问题:根据系统指令。 生成相关问题: - 类似于示例中的快速排序问题结束时生成的。 - 例如:1. 如何优化背包问题? 2. AtCoder上其他DP问题解析? 3. 动态规划的应用? 使用中文回答: - 全程用中文。 LaTeX格式: - 行内数学表达式如$DP[i][v]$, $O(N \times \text{total\_value})$ - 独立公式如状态转移方程单独成行。 完整回答框架: 1. **AtCoder dp_e题目解析** - 简述题目。 2. **题目描述** - 描述输入输出。 3. **解题思路** - 分析难点。 - 提出基于价值的DP。 - 状态转移方程。 4. **代码实现** - 提供Python代码。 5. **生成相关问题** 引用标识: - 在适当地方添加[^2], [^3]等。 现在,基于引用内容定制: - 引用[1]建议从入门开始,但用户已经指定dp_e,可以不直接用。 - 引用[2]和[3]关于DP基础,可以引用。 - 引用[4]是位运算优化,虽不直接相关,但可以提及优化技巧。 最终生成相关问题: 1. 如何处理背包问题中的大容量情况? 2. AtCoder上其他动态规划问题如dp_f的解析? 3. 记忆化搜索在DP中的应用? </think>### AtCoder dp_e题目解析及解题思路 AtCoder的dp_e问题属于经典的动态规划(DP)序列,具体是“背包问题2”(Knapsack 2),源自AtCoder Educational DP Contest。该问题在约束条件下有独特的优化挑战,区别于标准背包问题。下面我将逐步解析题目、解题思路和实现方法。内容参考了动态规划的核心概念[^2]和优化策略[^3],确保分析完整可靠。 #### 1. **题目描述** dp_e的题目是背包问题(Knapsack Problem)的变种: - **输入**:给定$N$个物品,每个物品有重量$w_i$和价值$v_i$,以及背包容量$W$。 - **输出**:选择物品子集,使得总重量不超过$W$,且总价值最大化。 - **约束**: - $N \leq 100$(物品数少), - $W \leq 10^9$(背包容量极大), - $v_i \leq 10^3$(价值较小,总价值最大$100 \times 1000 = 10^5$)。 关键难点:由于$W$巨大,直接使用基于重量的DP(时间复杂度$O(NW)$)会超出内存和时间限制(例如,$W=10^9$时需要$10^9$次操作,不可行)。因此,需要优化策略。 #### 2. **解题思路** 动态规划的核心是识别“重叠子问题”和“最优子结构”[^2]。针对dp_e,标准背包DP(定义$dp[i][j]$为前$i$个物品在容量$j$下的最大价值)不可行。优化思路转向**基于价值的DP**: - **状态定义**:定义$dp[i][v]$为考虑前$i$个物品时,达到总价值$v$所需的最小重量。 - 为什么有效?因为总价值上限小($ \leq 10^5$),状态空间可控。 - **状态转移方程**: 对于每个物品$i$和每个可能价值$v$,有两种选择: - 不选物品$i$:$dp[i][v] = dp[i-1][v]$ - 选物品$i$:$dp[i][v] = \min(dp[i][v], dp[i-1][v - v_i] + w_i)$ 数学表达为: $$ dp[i][v] = \min \begin{cases} dp[i-1][v] \\ dp[i-1][v - v_i] + w_i \quad (\text{if } v \geq v_i) \end{cases} $$ - **初始状态**: - $dp[0][0] = 0$(考虑0个物品,价值0时重量为0) - $dp[0][v] = \infty$(价值$v > 0$时不可达) - **目标答案**:遍历所有$v$,找到最大$v$使得$dp[N][v] \leq W$(即最小重量不超过$W$的最大价值)。 - **优化**: - **空间优化**:DP数组可降为一维($dp[v]$),通过逆序遍历$v$避免覆盖问题。 - **时间复杂度**:$O(N \times V_{\text{max}})$,其中$V_{\text{max}} = 10^5$,效率高(约$100 \times 10^5 = 10^7$次操作)。 这种优化利用了价值小的特性,避免了大容量的计算瓶颈[^3]。 #### 3. **代码实现(Python)** 以下是Python实现,基于上述思路。代码简洁,注释详细: ```python def main(): import sys data = sys.stdin.read().split() n = int(data[0]) W = int(data[1]) weights = [] values = [] index = 2 for i in range(n): weights.append(int(data[index])) values.append(int(data[index + 1])) index += 2 # 计算总价值上限 max_value = sum(values) # 初始化一维DP数组,dp[v]表示达到价值v的最小重量 dp = [10**18] * (max_value + 1) # 初始化为极大值 dp[0] = 0 # 基础状态 # 动态规划过程 for i in range(n): # 逆序遍历价值,避免覆盖 for v in range(max_value, values[i] - 1, -1): if dp[v - values[i]] != 10**18: # 确保前状态可达 dp[v] = min(dp[v], dp[v - values[i]] + weights[i]) # 查找最大有效价值 ans = 0 for v in range(max_value, -1, -1): if dp[v] <= W: ans = v break print(ans) if __name__ == '__main__': main() ``` **代码说明**: - 读取输入数据,包括物品数和容量。 - 定义DP数组,大小由总价值上限决定($10^5 + 1$)。 - 遍历每个物品,更新DP状态(逆序确保正确性)。 - 最后从高价值向低遍历,找到第一个$dp[v] \leq W$的$v$作为答案。 此方法高效解决了大$W$问题,时间复杂度$O(N \times \text{total_value})$,空间复杂度$O(\text{total_value})$。 #### 4. **关键点总结** - **为什么有效**:价值小、容量大的场景下,基于价值的DP避免了资源浪费[^2]。 - **常见错误**:尝试基于重量的DP会导致超时;必须优化状态定义。 - 在AtCoder比赛中,此题考察DP优化能力,建议通过实践加深理解[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值