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\n", 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\n", ans);
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM