AtCoder Beginner Contest 175 D.Moving Piece
发布日期:2021-06-22 22:48:23 浏览次数:3 分类:技术文章

本文共 1804 字,大约阅读时间需要 6 分钟。

AtCoder Beginner Contest 175 D.Moving Piece

在这里插入图片描述

最近忙于复习,今天实在复习不下去了就来补一下这题,比赛时没有考虑周全,WA了8个点,其实就差一点了,这题我的思路是这样的:
首先计算每个循环节的长度,对某段长度 l e n len len,求出 [ 1 , l e n ] [1,len] [1,len] 区间内的前缀和,这是预处理过程,很容易实现。题目的难点在于至多 k k k 次而非正好 k k k 次,所以要分情况讨论,对某个循环节长度 l e n len len

  • k < = l e n k<=len k<=len,很简单,取最大前缀和即可~
  • k > l e n k>len k>len,我们要仔细考虑,此时如果前缀和 s u m [ l e n ] ≤ 0 sum[len]\leq0 sum[len]0,那么我们取的循环节越多答案无疑越小,所以只需要取最大前缀和即可,也即和第一种情况一样;如果前缀和 s u m [ l e n ] > 0 sum[len]>0 sum[len]>0,此时我们发现循环节取得越多答案就越大,最多取的个数无疑是 n u m = ⌊ k l e n ⌋ num=\lfloor\frac{k}{len}\rfloor num=lenk,那么就相当于选一个 k % l e n k\%len k%len 里的最大前缀和加上前面 n u m num num 个前缀和的和,即 a n s = m a x { s u m [ k % l e n ] } + n u m ∗ s u m [ l e n ] ans=max\lbrace sum[k\%len]\rbrace+num*sum[len] ans=max{
    sum[k%len]}+
    numsum[len]
    此处有个小细节,就是当 k % l e n = 0 k\%len=0 k%len=0 时,我们个数要减 1 1 1,空一个循环节出来,以便和上面的取余统一,其实答案并没有变化,简便写法而已~

反正是挺考验思维的,好题b( ̄▽ ̄)d ,AC代码如下:

#include
using namespace std;typedef long long ll;const int N=5e3+5;int n;ll k,a[N],p[N],cnt[N]={
0},sum[N][N]={
0};ll dfs(ll i){
ll u=i,num=1,pos=1; while(p[i]!=u){
num++; i=p[i]; sum[u][pos]=sum[u][pos-1]+a[i]; pos++; } sum[u][pos]=sum[u][pos-1]+a[u]; return num;}int main(){
cin>>n>>k; for(int i=1;i<=n;i++) cin>>p[i]; for(int i=1;i<=n;i++) cin>>a[i]; ll ans=-1e18; for(int i=1;i<=n;i++){
cnt[i]=dfs(i); ll mx1=-1e18,mx2=-1e18; for(int j=1;j<=cnt[i];j++){
mx1=max(mx1,sum[i][j]); } for(int j=1;j<=(k%cnt[i]?k%cnt[i]:cnt[i]);j++){
mx2=max(mx2,sum[i][j]); } if(k>cnt[i]){
ll num=(k%cnt[i])?k/cnt[i]:k/cnt[i]-1; ans=max(ans,max(mx1,num*sum[i][cnt[i]]+mx2)); } else ans=max(ans,mx2); } cout<

转载地址:https://zaizai.blog.csdn.net/article/details/108150410 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:基于FPGA实现LED的闪烁——HLS
下一篇:机器学习——sklearn实现决策树(隐形眼镜预测和鸢尾花分类)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月04日 01时40分23秒