题意:
u1s1,题意真难懂
有n个时间,每个时间给你两个操作,第一个是k=k+x,第二个是k=k∗x,且可以执行[0,y]次,(在第i个时间点,必须应用第i个操作)
k 初始状态为0,
现在让你依次输出从1到m,到达每个数最少的操作次数
题解:
满脑子都是暴力。。但是暴力肯定不行
有点背包问题的感觉?但是第二种操作怎么都不能有效实现
看来终究还是暴力
根据题意可以知道最后的步数范围也就是[1,n]
最直接暴力是O(n*m^2),遍历[1,n],尝试[0,y]次相应操作,y的范围是[0,m]
比如原本能到的数是[3,11],现在x =4,y = 4,对于每个数更新的时候遍历到的集合就是[3,7,11,15,19]和[11,15,19,23,27],11的位置重复出现,所以当我们加数的时候,如果当前数已经存在,就直接break
总结:
先将所有位置初始化为inf,第0位是0
每次从m到0循环,看哪个数已经被确定了(第一次因为只有位置0还未确定,所以会从0开始),然后就在那个数的基础上继续扩展,出现已经确定的就break
复杂度是(n * m * 2)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
const int N = 1e6+7,INF = 1e9;
int ans[N];
int main()
{
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) ans[i] = INF;
for(int cur=1;cur<=n;cur++)
{
ll t,x,y;
scanf("%lld%lld%lld",&t,&x,&y);
for(int i=m;i>=0;i--)
{
if(ans[i] == INF) continue;
ll z = i;
for(int j=1;j<=y;j++)
{
if(t == 1) z = z + (x + 100000 - 1) / 100000;
else z = (z * x + 100000 - 1) / 100000;
if(z > m) break;
if(ans[z] < INF) break;
ans[z] = cur;
}
}
}
forn(i,1,m) printf("%d ",ans[i] == INF ? -1 : ans[i]);puts("");
return 0;
}