USACO 3.1 丑数

题目:https://www.luogu.org/problemnew/show/P2723

强烈谴责quq:这题根本不是黄题!!

根据题意,若令丑数集合为f,目前在第i个丑数,我们要判断f[i]的值

由于现在的丑数都是由另一个丑数乘以个数得来(我们假设f[0] = 1),利用类似dp的思想,我们知道f[i] = min(f[t] * a[j]),其中f[t]表示之前的丑数,j for 1 - k; 找到最小的值即可

直接这么做是O(n^2k)的,凉的很彻底orz

考虑优化:由于f是递增的,因此对于每一个j,枚举到第一个满足条件的t即可跳出

这么做理论复杂度依然没变,继续考虑优化

假设我们已经计算完f[i - 1],它可以由f[t] * a[j]得来,那么在计算f[i]时,枚举f只能从t开始,因为<t的f的值都不符合f[i - 1]的条件,自然不可能符合f[i]

那么用一个b数组记录j的上一个的t,在枚举时从b[j]开始即可

这样的复杂度变为O(nk + n),可以AC

以上

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<climits>
using namespace std;
const int maxn = 1e5 + 1;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
int k,n;
int a[105],f[maxn];
int b[105];
//f[t] * a[j] > f[i - 1]
int main()
{
    k = read(),n = read();
    for(int i = 1;i <= k;i++)
        a[i] = read();
    f[0] = 1;
    for(int i = 1;i <= n;i++)
        {
            int minm = INT_MAX;
            for(int j = 1;j <= k;j++)
                for(int t = b[j];t < i;t++)
                        if(f[t] * a[j] > f[i - 1])
                        {
                            minm = min(minm,f[t] * a[j]);
                            b[j] = t;
                            break;
                        }
            f[i] = minm;
        }
    printf("%d",f[n]);
}

 

posted on 2018-11-24 09:45  L_M_A  阅读(163)  评论(0编辑  收藏  举报

导航