【XJOI】小H的硬币游戏

题目链接(别想了)

小H的硬币游戏

题目描述

小H参加了一场神秘的游戏。游戏中有\(n\)堆硬币,第\(i\)堆价值\(a_i\)。每次小H可以选择编号相差\(k\)的硬币同时拿走。注意拿走后硬币不进行重标号。小H想知道最多能拿走多大价值的硬币。

输入格式:

第一行两个整数\(n\),\(k\)
第二行\(n\)个整数。第\(i\)个整数表示\(a_i\)

输出格式:

一行一个整数,表示拿走硬币的最大价值。

样例输入:

7 3
7 5 8 6 4 3 2

样例输出:

33

数据规模:

对于\(20%\)的数据,\(n<=20\)
对于\(40%\)的数据,\(n<=2000\)
对于另外\(20%\)的数据,\(k<=10\)
对于\(100%\)的数据,\(n<=100000\),\(k<=n\),\(ai<=1000000000\)

时间限制

1s

内存限制

256M

题解

题目要求给\(n\)个数,每对序号相差\(k\)的数可以被取走,求取走的数的和最大为多少。
因为每次取的数对序号相差必须为\(k\),所以如果一个数的序号为\(x\),那么对这个数有影响的数的序号为\(a*k+x%k\)
那么我们可以把这\(n\)个数根据它们的序号\(modk\)的值分成\(k\)个集合,只有集合内的数才能互相影响。
接下来直接\(dp\)就行了。
\(dp[j]\)表示前\(k\)个数在\(k\)所在的集合内所能取到的最大值为多少。
转移方程为:\(dp[j]=max(dp[j-k],dp[j-2*k]+a[j-k]+a[j])\)
\(k<j<=2*k\)时,\(dp[j]=a[j-k]+a[j]\)
最后在\(j+k>n\)时(这个集合内的最后一个元素加入集合后)把\(dp[j]\)加到\(ans\)里面去。
上代码:

#include<bits/stdc++.h>
using namespace std;
int n,k;
long long a[100009];
long long ans,dp[100009];
int main(){
    scanf("%d%d",&n,&k);
    for(int j=1;j<=n;j++)
        scanf("%lld",&a[j]);
    for(int j=1;j<=n;j++){
        if(j-k>0 && j<=2*k) dp[j]=a[j-k]+a[j];
        if(j-2*k>0) dp[j]=max(dp[j-k],dp[j-2*k]+a[j-k]+a[j]);
        if(j+k>n) ans+=dp[j];
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/linjiale/p/11644068.html