2019中国大学生程序设计竞赛-女生专场(重现赛)部分题解C-Function(贪心+优先队列) H-clock(模拟)

Function

题目链接

Problem Description

wls 有 n 个二次函数 Fi(x) = aix2 + bix + ci (1 ≤ i ≤ n).
现在他想在∑ni=1xi = m 且 x 为正整数的条件下求∑ni=1Fi(xi)的最小值。
请求出这个最小值。

Input

第一行两个正整数 n, m。
下面 n 行,每行三个整数 a, b, c 分别代表二次函数的二次项, 一次项,常数项系数。
1 ≤ n ≤ m ≤ 100, 000
1 ≤ a ≤ 1, 000
−1, 000 ≤ b, c ≤ 1, 000

Output

一行一个整数表示答案。

Sample Input

2 3
1 1 1
2 2 2

Sample Output

13

解题思路:

利用结构体维护每个函数f(x+1)-f(x)的差值,一开始将所有函数x置为1,贪心,优先取差值小的函数,x+1并更新差值重新放入优先队列中直至用完m-n个数为止

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e6 + 7;
const ll MAXM = 1e3 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
struct node
{
    ll a, b, c;
    ll mark;
    ll x;
    bool operator<(const node &t) const
    {
        return mark > t.mark;
    }
};
int main()
{
    ll n, m;
    while (~scanf("%lld%lld", &n, &m))
    {
        priority_queue<node> pq;
        ll ans = 0;
        for (int i = 0; i < n; i++)
        {
            node t;
            scanf("%lld%lld%lld", &t.a, &t.b, &t.c);
            ans += t.a + t.b + t.c;
            t.x = 1;
            t.mark = t.a * (2 * t.x + 1) + t.b;
            pq.push(t);
        }
        for (int i = 0; i < m - n; i++)
        {
            node temp = pq.top();
            pq.pop();
            temp.x++;
            temp.mark = temp.a * (2 * temp.x + 1) + temp.b;
            pq.push(temp);
            ans += temp.a * (2 * temp.x - 1) + temp.b;
        }
        printf("%lld
", ans);
    }
    return 0;
}

Clock

题目链接

Problem Description

wls 有一个钟表,当前钟表指向了某一个时间。
又有一些很重要的时刻,wls 想要在钟表上复现这些时间(并不需要依次复现)。我们可以顺时针转动秒针,也可以逆时针转动秒针,分针和时针都会随着秒针按规则转动,wls 想知道秒针至少转动多少角度可以使每个时刻至少都会被访问一次。
注意,时钟上的一种时针分针秒针的组合,可以代表两个不同的时间。

Input

第一行一个整数 n 代表有多少个时刻要访问。
第二行三个整数 h,m,s 分别代表当前时刻的时分秒。
最后n行每一行三个整数 hi,mi,si 代表每个要访问的时刻的时分秒。
1 ≤ n ≤ 86, 400
0 ≤ h, hi < 24
0 ≤ m, mi, s, si < 60

Output

输出一行一个数代表秒钟转的角度,答案保留两位小数。

Sample Input

1
0 1 0
0 1 1

Sample Output

6.00

解题思路:

总共有一直顺时针转,一直逆时针转,先逆时针后顺时针,先顺时针后逆时针转四种情况,直接模拟

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e6 + 7;
const ll MAXM = 1e3 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
int main()
{
    int n, h, m, s;
    int h1, m1, s1;
    int ans = 0;
    int suma = 12 * 3600;
    while (~scanf("%d", &n))
    {
        scanf("%d%d%d", &h, &m, &s);
        h %= 12;
        int start = h * 3600 + m * 60 + s;
        ans = 0;
        int ed1 = start, ed2 = start; //倒回去最接近0,顺下去最接近12
        int st1 = 0, st2 = suma;      //倒回去最接近起点,顺下去最接近起点
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d%d", &h1, &m1, &s1);
            h1 %= 12;
            int sum = h1 * 3600 + 60 * m1 + s1;
            ed2 = max(ed2, sum);
            ed1 = min(ed1, sum);
            if (sum < start)
                st1 = max(st1, sum);
            else if (sum > start)
                st2 = min(sum, st2);
        }
        ans = min(min(suma - (start - st1), suma - (st2 - start)), min(start - ed1 + ed2 - ed1, ed2 - start + ed2 - ed1));
        ans *= 6;
        printf("%d.00
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/graytido/p/11185452.html