518E (贪心)

 给一个拥有n个元素、可能含“?”的序列,通过构造使得所有数的绝对值之和最小,同时使得序列的连续的k项之和是严格递增的。
题目传送门


要满足连续K项和递增,即a[1]+a[2]+……+a[k]<a[2]+a[3]+……+a[k+1]<……<a[n-k+1]+a[n-k+2]+……+a[n]
只需:a[1]<a[k+1]<a[2*k+1]<……
          a[2]<a[k+2]<a[2*k+2]<……
          ……
      
一开始想到的是枚举起点从1到n-k+1,终点到n。统计出现?的次数,每当出现一个非?的数时,求出之前所有?的值。(具体求法是:先求满足要求的最小值,即最左端?的值,要使绝对值之和最小,则之后的数在前面的基础上+1即可。)
但这样枚举的话,会出现问题,比如下面这种情况:
4 3
? ? ? ?
这里并未出现非?的数,因此会出错。

于是想到在输入完n个数后,再在其末尾添加k个大数inf+1,枚举终点范围变为n+k,然而这样还是无法解决问题。因为起点的枚举范围是1到n-k+1,也就是说,范围不够,这样枚举的话,有些值是无法求到的,比如上面的样例,第三个?就无法求出。起点的枚举范围应该为1到k,这样可保证求出所有的?的值。

 

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
char s[20];
int a[200005];
int main()
{
    int n,k,i,j;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i)
    {
        scanf("%s",s);
        if(s[0]=='?') a[i]=inf;
        else sscanf(s,"%d",&a[i]);
    }
    for(i=n+1;i<=n+k;++i)
    {
        a[i]=inf+1;
    }
    for(i=1;i<=k;++i)
    {
        int cnt=0,pre=-inf;
        for(j=i;j<=n+k;j+=k)
        {
            if(a[j]==inf) ++cnt;
            else
            {
                if(a[j]-pre<=cnt)
                {
                    puts("Incorrect sequence");
                    return 0;
                }
                int num=max(pre+1,min(-cnt/2,a[j]-cnt));
                for(int t=cnt;t>0;--t) a[j-t*k]=num++;
                cnt=0;
                pre=a[j];
            }
        }
    }
    for(i=1;i<n;++i) printf("%d ",a[i]);
    printf("%d\n",a[i]);
    return 0;
}


 

### 贪心算法策略的实现与解释 贪心算法是一种通过局部最优解来寻找全局最优解的方法。它在每一步都选择当前状态下看起来最佳的选择,而不考虑未来的后果。这种方法并不总是能找到全局最优解,但在某些情况下非常有效。 #### 局部最优与全局最优的关系 贪心算法的核心在于假设每次做出的最佳选择能够最终导向整体上的最佳解决方案。然而,在实际应用中,这种假设可能不成立,因此需要仔细分析问题特性以判断是否适合采用该方法[^1]。 #### 实现示例:找零钱问题 下面是一个经典的例子——如何用最少数量的硬币凑成指定金额: ```python def coin_change(coins, amount): coins.sort(reverse=True) # 将面额按降序排列 count = 0 for coin in coins: if amount >= coin: # 如果当前硬币可以使用 num_coins = amount // coin # 计算能使用的最大数目 count += num_coins # 增加计数器 amount -= num_coins * coin # 减少剩余金额 if amount == 0: # 提前结束循环 break return count if amount == 0 else -1 # 若无法完全支付返回-1 # 测试代码 coins = [25, 10, 5, 1] # 美元硬币面额 amount = 63 # 需要找的钱数 print(coin_change(coins, amount)) # 输出结果应为6 (25*2 + 10*1 + 5*1 + 1*3) ``` 此程序展示了如何利用贪心法解决特定条件下的最小化问题。需要注意的是,只有当硬币体系满足某种特殊性质(如美国货币单位)时,上述方法才适用;对于其他情况,则需更复杂的动态规划方案替代之[^2]。 #### 数据预处理中的贪婪选取 另一个应用场景是在数据科学领域内的特征工程阶段。比如当我们面对大量维度的数据集而希望快速筛选出最具代表性的子集作为输入变量参与建模训练过程的时候,就可以运用类似的思维模式来进行初步过滤操作[^3]: ```python import pandas as pd def greedy_feature_selection(dataframe, target_column, threshold=0.8): selected_features = [] remaining_columns = list(set(dataframe.columns)-set([target_column])) while True: best_corr = None best_col = '' for col in remaining_columns: corr_value = abs(dataframe[target_column].corr(dataframe[col])) if not best_corr or corr_value > best_corr: best_corr = corr_value best_col = col if best_corr is None or best_corr < threshold: break selected_features.append(best_col) remaining_columns.remove(best_col) return selected_features df_example = pd.DataFrame({ 'A': [1, 2, 3], 'B': [-1,-2,-3], 'C': [9,8,7], 'D': [4,5,6] }) result = greedy_feature_selection(df_example,'D') print(result) # 可能得到 ['A', 'C'] ``` 这段脚本定义了一个简单的函数用于基于皮尔逊相关系数挑选最相关的属性列直到达到设定阈值为止。这同样体现了逐次逼近的思想方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值