[CF1498D] Bananas in a Microwave (DP)

题面&翻译

题解

虽然 m m m 很大,但是 n n n 很小,因此题目允许我们在 O ( n m ) O(nm) O(nm) 以内解决这道题。

定义一个 dp[i][j]=0/1
如果是 i i i 个操作时能不能停在 j j j的话,我们会发现,从第一个最小的 i i i 满足 d p [ i ] [ j ] = 1 dp[i][j]=1 dp[i][j]=1 开始,后面的 d p [ i + 1... n ] [ j ] dp[i+1...n][j] dp[i+1...n][j] 一定都为 1 了,因为后面的操作都可以令 a = 0 a=0 a=0 然后不动。因此我们完全没必要定义第一维。

那就定义一个 dp[i] 表示 i i i 时的最小可能操作
我们会发现,由于 y i y_i yi 的限制,我们缺少次数的信息,无法转移,因此要同时记录该信息。

dp[i][j] 表示 i i i 时的最小可能操作,满足此时操作已经执行了 j j j总行了吧?
事实上这很荒谬。首先, i i i 时的最小可能操作是确定的,跟你强制的这个执行次数 “j” 并没关系,而且更严谨地说,操作数是因,执行次数是果,总不能把果放进状态吧。其次,既然最小操作数确定,那么到达 i i i 时该操作的执行次数肯定越少越好。

因此我们定义 (pair<int,int>) dp[i] ,第一个值表示 i i i 时的最小可能操作,第二个值表示到 i i i 时的最小执行次数
此时两个 pair 取较小的,刚好是先比较第一位,再比较第二位。
方便起见,令 N e x t i ( k ) {\rm Next}_i(k) Nexti(k) 表示从位置 k k k 开始,执行一次 i i i 类操作后走到的位置,那么有如下转移:

  1. { d p [ i ] . f i r s t , d p [ i ] . s e c o n d + 1 } → d p [ N e x t d p [ i ] . f i r s t ( i ) ] \{dp[i].{\rm first},dp[i].{\rm second}+1\}\rightarrow dp[{\rm Next}_{dp[i].{\rm first}}(i)] {dp[i].first,dp[i].second+1}dp[Nextdp[i].first(i)]
  2. { j , 1 } → d p [ N e x t j ( i ) ] \{j,1\}\rightarrow dp[{\rm Next}_{j}(i)] {j,1}dp[Nextj(i)]

第一个转移的条件是执行次数没到 y y y 的限制,第二个转移的条件是 j j j 大于当前的 d p [ i ] . f i r s t dp[i].{\rm first} dp[i].first

状态数 O ( m ) O(m) O(m),转移复杂度 O ( n ) O(n) O(n) ,总复杂度 O ( n m ) O(nm) O(nm).

CODE

#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
#define int LL
LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
int n,m,i,j,s,o,k;
int ti[MAXN],yy[MAXN];
LL xx[MAXN];
int tm[MAXN],ai[MAXN];
void add(int i,int tim,int Ai) {
	if(i < 1 || i > n) return ;
	if(tim < tm[i]) tm[i]=tim,ai[i]=Ai;
	else if(tim == tm[i]) ai[i] = min(ai[i],Ai);
//	printf("  %d : %d,%d\n",i,tm[i],ai[i]);
	return ;
}
int adnm(LL x,int i) {return (x+100000ll*i+99999ll)/100000;}
int munm(LL x,int i) {return (x*i+99999ll)/100000;}
signed main() {
	m = read();n = read();
	for(int i = 1;i <= m;i ++) {
		ti[i] = read();
		xx[i] = read();
		yy[i] = read();
	}
	for(int i = 1;i <= n;i ++) tm[i] = 0x3f3f3f3f;
	tm[0] = 0; ai[0] = 0;
	for(int i = 0;i <= n;i ++) {
		if(i > 0) printf("%lld ",tm[i] >= 0x3f3f3f3f ? -1:tm[i]);
		if(tm[i] < 0x3f3f3f3f) {
			int t = tm[i];
			if(ti[t] == 1 && ai[i] < yy[t]) add(adnm(xx[t],i),t,ai[i]+1);
			else if(ti[t] == 2 && ai[i] < yy[t]) add(munm(xx[t],i),t,ai[i]+1);
			for(int j = t+1;j <= m;j ++) {
				if(ti[j] == 1) add(adnm(xx[j],i),j,1);
				else if(ti[j] == 2) add(munm(xx[j],i),j,1);
			}
		}
	}ENDL;
	return 0;
}
posted @ 2021-05-04 12:27  DD_XYX  阅读(24)  评论(0编辑  收藏  举报