D. Bananas in a Microwave

D. Bananas in a Microwave

题意:

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;
}

猜你喜欢

转载自blog.csdn.net/qq_35975367/article/details/115346657