zoukankan      html  css  js  c++  java
  • 题解 [BZOJ4368][IOI2015]boxes纪念品盒

    题面

    解析

    可以发现,发纪念品有三种方式:

    1. 从左边走再原路返回.
    2. 从右边走再原路返回.
    3. 走一圈.

    注意到,第三种走法最多只会走一次,

    因为如果走了多次,那发放的物品数量就会>=(2k),

    那么一定有半边的数量>=(k).

    因此就可以转化为一次1/2操作加一次3操作(先发掉(k)个).

    那么我们可以先DP一下1/2操作发前(i)个纪念品所用的时间(f1[i]/f2[i]),

    那没有3操作的时间就是f1+f2,

    考虑走一圈的情况,枚举从左边走发的纪念品数更新答案即可.

    code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define int long long
    #define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    
    const int N=10000005;
    int n,K,L,p[N];
    int st1[N],st2[N],tp1,tp2;
    int f1[N],f2[N];
    
    signed main(){
    	n=read();K=read();L=read();
    	for(int i=1;i<=n;i++){
    		p[i]=read();
    		if(p[i]<=L>>1) st1[++tp1]=p[i];
    		else st2[++tp2]=L-p[i];
    	}
    	for(int i=1;i<=tp2>>1;i++) swap(st2[i],st2[tp2-i+1]);
    	for(int i=1;i<=tp1;i++)
    		f1[i]=(i<=K? st1[i]:st1[i]+f1[i-K]);
    	for(int i=1;i<=tp2;i++)
    		f2[i]=(i<=K? st2[i]:st2[i]+f2[i-K]);
    	int ans=(f1[tp1]+f2[tp2])<<1;
    	for(int i=tp1-K;i<=tp1;i++){//至少要从tp1开始枚举不然发不完
    		ans=min(ans,((f1[i]+f2[max((int)0,n-K-i)])<<1)+L);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    go 学习笔记---chan
    golang学习笔记---Goroutine
    golang ---Learn Concurrency
    golang ----并发 && 并行
    golang 学习笔记 使用cmd
    并发程序与并行程序
    golang学习笔记 ---interface
    golang --- map如何判断key是否存在
    golang学习 ---defer语句
    golang --for语句
  • 原文地址:https://www.cnblogs.com/zsq259/p/11416046.html
Copyright © 2011-2022 走看看