牛客练习赛86 C. 取钱(DP)

传送门
分析见代码注释

#include 

using namespace std;
//-----pre_def----
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
#define rif(i, a, b) for (int i = (a); i >= (b); i--)
#define endl '\n'
#define init_h memset(h, -1, sizeof h), idx = 0;
#define lowbit(x) x &(-x)

//---------------
const int N = 2e5 + 10;
int n, m, d[N];
LL a[N], sum[N], cnt[N];
void init() {}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    int StartTime = clock();
#endif
    scanf("%d", &n);
    fir(i, 1, n) scanf("%lld", &a[i]);
    /*
    如果要取的面额大于等于a[i]-->atm直接吐出一张a[i]的纸币
    预处理出不超过当前钞票面额的最多钞票数
    */
    a[n + 1] = 1e18;
    fir(i, 1, n)
    {
        //在总额不超过a[i+1]的前提下,第i张纸币最多取t张,此时保证了纸币数量最大且总额不超(如果大于等于a[i+1]了,那么只需要一张a[i+1]就行了)
        // sum[i-1]+t*a[i] < a[i+1]
        LL t = (a[i + 1] - sum[i - 1] - 1) / a[i];
        cnt[i] = cnt[i - 1] + t;
        sum[i] = sum[i - 1] + t * a[i];
    }
    scanf("%d", &m);
    fir(i, 1, m)
    {
        LL x;
        scanf("%lld", &x);
        int tmp = lower_bound(sum + 1, sum + 1 + n, x) - sum;
        LL res = cnt[tmp - 1] + (x - sum[tmp - 1]) / a[tmp];
        //(x - sum[tmp - 1]) / a[tmp] 表示:还能取多少的第tmp大面值的纸币
        printf("%lld %lld\n", sum[tmp - 1] + (x - sum[tmp - 1]) / a[tmp] * a[tmp], res);
    }
#ifndef ONLINE_JUDGE
    printf("Run_Time = %d ms\n", clock() - StartTime);
#endif
    return 0;
}

你可能感兴趣的:(DP,c语言,算法,数据结构,动态规划)