ABC 374 F - Shipping

题目链接

发货时间不宜推迟,一段从开始到发货的时间,要么是捡起该组第一个开始,然后捡起最后一个结束的紧密的时间节点,要么是缓冲期x结束之后立刻发货

那么发货时间段就只有两种情况

题目给的数组a[i]

以及a[i]+mk

m的取值范围是1到n,因为最多只有n个,最多就只能缓冲n段,这是最极限的情况

然后预处理完之后大概就是有n方种

然后考虑dp方程

方程的设置要有一定的限制性,如何应对两次发货之间空格x,这个要在dp方程的含义中又限制

d p [ i ] [ j ] dp[i][j] dp[i][j] i是某个节点,是一轮发货的开始,j是本次发货第一个的火舞 ,dp[i][j]代表的数是不算上这一轮发货的,前i-1个节点,发j-1个货的最小值

如若第i个节点什么事都不干的话,就把dp[i][j]的状态过度给dp[i+1][j]

然后我们每次处理,都预定一个最近的,差值比x大的时间节点next,我们把时间节点i获得的状态转移给next,然后最后一组的时候再结算

#include <bits/stdc++.h>
using namespace std;
const int N = 1e2+5;
#define int long long
const int INF = 4e18+5;
#define F(i,l,r) for(int i=l;i<=r;i++)
#define R(i,l,r) for(int i=r;i>=l;i--)
#define vv vector
#define fi first
#define se second
#define pii pair<int,int>
typedef long long ll;
const int mod = 998244353; 
//const int mod = 1e9+7; 
const int M = 1e7+5;
int a[N],b[N],c[N],d[N],vis[N],pri[N],ans1[N],ans2[N],dp[N*N][N]; 
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
int n,m,k,ans,x,y,n0,n2,m0,m2,op1,op2;
string s;
map<pii,int>mp;
map<int,int>mmap;
double p[N];//到达点i的概率 
//char mp[1005][1005];
//vector<int>v1[N],v2[N];
int lowbit(int x) {
	return x&-x;
}
char xx[N];
bool temp;
int kuai(int x,int y){
	int sum=1;
	x%=mod;
	while(y){
		if(y%2){
			y--;
			sum*=x;
			sum%=mod;
		  }
	  x*=x;
	  y/=2;
	  x%=mod;
	}
	return sum;
}
struct node{
	int shu;
	int id;
}jie[N];
bool cmp(node x,node y){
	return x.shu<y.shu;
}
void solve()
{
	cin>>n>>k>>m;//一次能装多少    发货了下次发货要多少时间 
	F(i,0,n-1) cin>>a[i]; vector<int>clk;
	F(i,0,n-1) F(j,0,n) clk.push_back(a[i]+j*m);
	sort(clk.begin(),clk.end());
	clk.erase(unique(clk.begin(),clk.end()),clk.end());
	int cs=clk.size(); ans=INF;
	//F(i,0,cs-1) cout<<clk[i]<<" ";
	vector<vector<long long>> dp(cs+1,vector<long long>(n,8e18)); dp[0][0]=0;
	int nxt=0;
	for(long long i=0;i<cs;i++){
    while(nxt<cs && clk[nxt]<clk[i]+m){nxt++;}
    for(long long j=0;j<n;j++){
      if(dp[i][j]>4e18){continue;}
      dp[i+1][j]=min(dp[i+1][j],dp[i][j]);

      long long mv=dp[i][j];
      for(long long p=j;p<min(j+k,n);p++){
        if(clk[i]<a[p]){break;}

        mv+=(clk[i]-a[p]);
		//cout<<mv<<"**"<<endl;
        if(p==n-1){
          // finish
          ans=min(ans,mv);
        }
        else if(nxt<cs){
          dp[nxt][p+1]=min(dp[nxt][p+1],mv);
        }
      }
    }
  }
	cout<<ans;
}
signed main() 
{
	ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0); // cin.tie(nullptr);
    int T = 1;                                                                                                                                                                                                                                                                    
    //cin >> T;
    for (int i = 1; i <= T; i++)
    {
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值