OnlyPersistVictory DayEight

休息了一天~

H

题意:
初始有 k = 0 k=0 k=0根香蕉,有两种操作可以使得香蕉的个数 k k k变化。
t = 1 t=1 t=1时,一次时间戳内可以进行 [ 0 , y ] [0,y] [0,y] k = k + x k=k+x k=k+x的操作, t = 2 t=2 t=2时,一次时间戳内可以进行 [ 0 , y ] [0,y] [0,y] k = k × x k=k\times x k=k×x的操作。问获得 [ 1 , m ] [1,m] [1,m]根香蕉的时间戳最小分别是多少,如果某个数量的香蕉不能获得,则输出 − 1 -1 1
数据范围:
1 ≤ n ≤ 200 , 1 ≤ m ≤ 1 0 5 , 1 ≤ t ≤ 2 , 0 ≤ y ≤ 1 0 5 , x = ⌈ x ′ 1 0 5 ⌉ 1\leq n\leq 200,1\leq m\leq 10^5,1\leq t\leq 2,0\leq y\leq 10^5,x=\lceil \frac{x'}{10^5} \rceil 1n200,1m105,1t2,0y105,x=105x
t = 1 t=1 t=1 1 ≤ x ′ ≤ 1 0 5 1\leq x'\leq 10^5 1x105;当 t = 2 t=2 t=2 1 ≤ x ′ ≤ 1 0 5 × m 1\leq x'\leq 10^5\times m 1x105×m

题解:
暴力的想法即模拟,时间复杂度为: O ( n m 2 ) O(nm^2) O(nm2)
考虑优化:
可以知道的是,我们在时间戳 i i i枚举 t i m e [ j ] time[j] time[j]作为更新之后状态的时间戳必须是 t i m e [ j ] time[j] time[j]可以到达。同时,我们从后向前枚举,保证新更新的时间戳都是由之前的状态更新而来的,类似 01 01 01背包优化空间复杂度的思想。当 t i m e [ j + c n t × x ] time[j+cnt\times x] time[j+cnt×x]已经存在了,那么可以知道的是从 t i m e [ j + c n t × x ] time[j+cnt\times x] time[j+cnt×x]开始枚举之后的状态的时间戳一定会比 t i m e [ j ] time[j] time[j]更远,所以如果 t i m e [ j + c n t × x ] time[j+cnt\times x] time[j+cnt×x]已经有了则无需继续枚举。乘法同理。

分析下时间复杂度:
枚举 n n n次操作和每次枚举 [ 0 , m ] [0,m] [0,m] m + 1 m+1 m+1个状态共 n × ( m + 1 ) n\times (m+1) n×(m+1)
此外每次只会枚举所有的已有时间戳的状态作为起点,同时每个点最多会被时间戳占用一次,因此总共最多占用 m m m次,因此 n n n次枚举最多只会使得 m m m个点每次被访问一次,因此总共上限是 n ( 2 m + 1 ) n(2m+1) n(2m+1)次,即 O ( n m ) O(nm) O(nm)的时间复杂度。

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = 1e5 + 10;
int ans[M];
int n, m;
ll t, x, y;

int main()
{
	scanf("%d%d", &n, &m);
	memset(ans, -1, sizeof ans);
	ans[0] = 0;
	for(int i = 1; i <= n; ++i) {
		scanf("%lld%lld%lld", &t, &x, &y);
		if(t == 1) x = (x + 99999) / 100000;
		
		for(int j = m; j >= 0; --j) {
			if(ans[j] == -1) continue;
			ll z = j;
			for(int k = 0; k < y; ++k) {
				if(t == 1) z += x;
				else z = (z * x + 99999) / 100000;
				if(z > m) break;
				if(ans[z] != -1) break;
				ans[z] = i;
			}
		}
	}
	for(int i = 1; i <= m; ++i) printf("%d%c", ans[i], (i == m) ? '\n' : ' ');	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值