CCPC 2016-2017, Finals

A. HDU 5999 The Third Cup is Free

简单模拟。

 

 

B. HDU 6000 Wash

n 件衣服, m 个洗衣机,k 个烘干机。每个洗衣机和烘干机需要不同的时间。问 n 件衣服洗完 + 烘干最小时间。

看做两部:洗 + 烘干,用洗需要时间长的去配烘干需要时间短的,所有衣服取max。

优先队列维护,取最小的,加上时长再放进去。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pr;


int main()
{
    int t;
    scanf("%d", &t);
    for (int ca = 1; ca <= t; ca++)
    {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);

        priority_queue<pr, vector<pr>, greater<pr> > q1, q2;
        LL x;
        for (int i = 1; i <= m; i++)
            scanf("%lld", &x), q1.push(pr(x, x));
        for (int i = 1; i <= k; i++)
            scanf("%lld", &x), q2.push(pr(x, x));

        vector<LL> a, b;
        LL ans = 0;
        for (int i = 1; i <= n; i++)
        {
            pr tmp = q1.top(); q1.pop();
            a.push_back(tmp.first); q1.push(pr(tmp.first + tmp.second, tmp.second));
        }
        int len = a.size();
        for (int i = 1; i <= n; i++)
        {
            pr tmp = q2.top(); q2.pop();
            q2.push(pr(tmp.first + tmp.second, tmp.second));
            ans = max(ans, a[len-i] + tmp.first);
        }

        printf("Case #%d: %lld\n", ca, ans);
    }
}

 

 

C. HDU 6001 Mr.Panda and Survey

容斥 + DFS

 

 

D. HDU 6002 Game Leader

优先队列贪心

 


E. HDU 6003 Problem Buyer

贪心。

 


F. HDU 6004 Periodical Cicadas

DP预处理 + exgcd

 


G. HDU 6005 Pandaland

给你一些边,求最小环。边数 <= 4000。

枚举每条边,设其长度为 inf 后求两端点的最短路,最后再把答案加上原本的边长。

最短路用堆优化的Dijkstra,若 dis + 边长 > ans直接停止,否则会TLE。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <set>
using namespace std;
typedef pair<int, int> pr;
const int INF = 0x3f3f3f3f;
const int maxn = 4000 + 100;
int n;
int sz = 0, tot;
int v[2*maxn], last[2*maxn], nxt[2*maxn], lo[2*maxn];
int dis[2*maxn], vis[2*maxn], ans;

void build(int x,int y,int z)
{
    sz++;
    v[sz] = y, nxt[sz] = last[x], last[x] = sz, lo[sz] = z;
    sz++;
    v[sz] = x, nxt[sz] = last[y], last[y] = sz, lo[sz] = z;
}

int Dijkstra(int s, int t, int extr)
{
    for (int i = 1; i <= tot; i++)
        dis[i] = INF, vis[i] = 0;
    dis[s] = 0;
    priority_queue<pr, vector<pr>, greater<pr> > q;
    q.push(pr(0, s));

    while(!q.empty())
    {
        pr node = q.top(); q.pop();
        int x = node.second, length = node.first;
        if (length + extr > ans) break;
        if (vis[x]) continue;
        vis[x] = 1;
        for (int i = last[x]; i; i = nxt[i])
            if (dis[v[i]] > dis[x] + lo[i])
            {
                dis[v[i]] = dis[x] + lo[i];
                q.push(pr(dis[v[i]], v[i]));
            }
    }
    return dis[t];
}

int main()
{
    int t;
    scanf("%d", &t);
    for (int ca = 1; ca <= t; ca++)
    {
        tot = sz = 0;
        memset(last, 0, sizeof(last));

        map<pr, int> mp;
        scanf("%d", &n);
        int x1, x2, y1, y2, x;
        for (int i = 1; i <= n; i++)
        {
            scanf("%d%d%d%d%d", &x1,&y1,&x2,&y2,&x);
            if (mp[pr(x1, y1)] == 0) mp[pr(x1, y1)] = ++tot;
            if (mp[pr(x2, y2)] == 0) mp[pr(x2, y2)] = ++tot;
            build(mp[pr(x1, y1)], mp[pr(x2, y2)], x);
        }

        ans = INF;
        for (int i = 1; i <= sz; i += 2)
        {
            int x = v[i], y = v[i+1];
            int tmplen = lo[i];
            lo[i] = lo[i+1] = INF;
            ans = min(ans, Dijkstra(x, y, tmplen) + tmplen);
            lo[i] = lo[i+1] = tmplen;
        }

        if (ans >= INF) ans = 0;

        printf("Case #%d: %d\n", ca, ans);
    }
}

 

 

H. HDU 6006 Engineer Assignment

n 个工程,每个工程都有一些需求的领域。 m 个工程师,每个工程师有几个擅长的领域,且仅能被分配到一个项目。

当且仅当一些工程师满足了项目的全部需求领域,这个项目才会被完成。问最多可以完成几个项目。

n,m都很小,预处理出每个项目需要的工程师,状态压缩 + 背包。

(x & j) == x时,证明 j 包含 x; j ^ x 就是 j 代表的集合减去 x 代表的集合。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
const int maxn = 10 + 10;

vector<int> a[maxn], b[maxn];
int e[maxn][1 << 11];
int dp[maxn][1 << 11];

int main()
{
    int t;
    scanf("%d", &t);
    for (int ca = 1; ca <= t; ca++)
    {
        int n, m, k, x;
        scanf("%d%d", &n, &m);

        for (int i = 1; i <= n; i++) a[i].clear();
        for (int j = 1; j <= m; j++) b[j].clear();
        memset(e, 0, sizeof(0));

        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &k);
            for (int j = 1; j <= k; j++)
                scanf("%d", &x), a[i].push_back(x);
        }
        for (int i = 1; i <= m; i++)
        {
            scanf("%d", &k);
            for (int j = 1; j <= k; j++)
                scanf("%d", &x), b[i].push_back(x);
        }

        for (int i = 1; i <= n; i++)
        {
            set<int> st;
            for (int j = 0; j < a[i].size(); j++) st.insert(a[i][j]);

            for (int j = 1; j < (1<<m); j++)
            {
                set<int> s2;
                for (int k = 0; k < m; k++)
                    if (j & (1<<k)) for (int l = 0; l < b[k+1].size(); l++) s2.insert(b[k+1][l]);

                set<int> :: iterator it;
                int flag = 1;
                for (it = st.begin(); it != st.end(); it++)
                    if (!s2.count(*it))
                    {
                        flag = 0;
                        break;
                    }

                e[i][j] = flag;
            }
        }

        for (int i = 1; i <= n; i++)
            for (int j = 1; j < (1<<m); j++)
            {
                dp[i][j] = dp[i-1][j];
                for (int x = 1; x < (1<<m); x++)
                if (e[i][x] && (x&j) == x)
                    dp[i][j] = max(dp[i][j], dp[i-1][j^x] + 1);
            }

        int ans = 0;
        for (int i = 1; i < (1<<m); i++)
            ans = max(ans, dp[n][i]);

        printf("Case #%d: %d\n", ca, ans);
    }
}

  

 

I. HDU 6007 Mr. Panda and Crystal

制造所有宝石都是可以用花费来衡量的。最短路跑出所有宝石的最小制作费用,然后完全背包就可以了。

一种宝石可以更新花费,当且仅当有一种配方的总花费小于它的花费。可以用vector记录配方信息,然后再用一个vector记录每个宝石的配方下标。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 300 + 10;
const int maxm = 400010;
const int INF = 0x3f3f3f3f;
 
 
int dis[maxn], weg[maxn];
int vis[maxn];
vector<int> a[maxn], aid[maxn], sum[maxn], tp[maxn];
int v[2*maxm], last[2*maxm], nxt[2*maxm];
int dp[maxm];
 
int n, m, k, sz;
 
void build(int x, int y)
{
    sz++;
    v[sz] = y, nxt[sz] = last[x], last[x] = sz;
}
 
bool relax(int x, int y)
{
    int siz = tp[y].size(), res = INF;
    for (int i = 0; i < siz; i++)
    {
        int to = tp[y][i], s = aid[to].size(), ans = 0, flag = 0;
        for (int j = 0; j < s; j++)
        {
            int ad = aid[to][j], sm = sum[to][j];
            if (dis[ad] == INF)
            {
                flag = 1;
                break;
            }
            ans += dis[ad] * sm;
        }
        if (flag == 0) res = min(res, ans);
    }
 
    if (dis[y] > res)
        return dis[y] = res, true;
    return false;
}
 
 
void SPFA()
{
    queue<int> q;
    memset(vis, 0, sizeof(vis));
 
    for (int i = 1; i <= n; i++)
        if (dis[i] != INF) q.push(i), vis[i] = 1;
 
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        for (int i = last[x]; i; i = nxt[i])
            if (relax(x, v[i]) && !vis[v[i]])
                vis[v[i]] = 1, q.push(v[i]);
        vis[x] = 0;
    }
}
 
 
int main()
{
    int t;
    scanf("%d", &t);
    for (int ca = 1; ca <= t; ca++)
    {
        sz = 0;
        memset(last, 0, sizeof(last));
 
        scanf("%d%d%d", &m, &n, &k);
        for (int i = 0; i < max(n, k); i++) aid[i].clear(), sum[i].clear(), tp[i].clear();
        //死在这里的clear了。不能只循环到n,因为k可能大于n。
 
        for (int i = 1; i <= n; i++)
        {
            int typ;
            scanf("%d", &typ);
            typ == 1 ? scanf("%d", &dis[i]):dis[i] = INF;
            scanf("%d", &weg[i]);
        }
 
        for (int i = 1; i <= k; i++)
        {
            int x, s, fr, d;
            scanf("%d%d", &x, &s);
            for (int j = 1; j <= s; j++)
            {
                scanf("%d%d", &fr, &d);
                build(fr, x);
                aid[i].push_back(fr), sum[i].push_back(d);
            }
            tp[x].push_back(i);
        }
 
        SPFA();
 
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; i++)
            for (int j = dis[i]; j <= m; j++)
                dp[j] = max(dp[j], dp[j-dis[i]]+weg[i]);
 
        printf("Case #%d: %d\n", ca, dp[m]);
    }
}

  

  

 

J. HDU 6008 Worried School

题意复杂。

set判重即可,分别求出两个名次。注意 region + final <= G-1 时是 "ADVANCED!" 。

 

 

K. HDU 6009 Lazors

模拟。

 


L. HDU 6010 Daylight Saving Time

模拟。只要处理出second Sunday in March first Sunday in November 是几号就可以了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
const int mon[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int run(int x)
{
    if (x%4 == 0 && x%100 != 0) return 1;
    if (x%400 == 0) return 1;
    return 0;
}

int day(int y, int m, int d)
{
    int sum = 0;
    for (int i = 2007; i < y; i++)
        sum += 365 + run(i);

    for (int i = 1; i < m; i++)
    {
        sum += mon[i];
        if (run[y] && i == 2) sum++;
    }

    sum += d;
    return sum%7;
}

int main()
{

    int t;
    scanf("%d", &t);

    for (int ca = 1; ca <= t; ca++)
    {
        int y, m, d, h, mi, s;
        scanf("%d-%d-%d %d:%d:%d", &y,&m,&d,&h,&mi,&s);
        int pst = 0, pdt = 0;

        int times = 0, Nov = 1, Mar = 1;
        for (int i = 1; i <= 30; i++)
        {
            if (!day(y, 11, i)) times++;
            if (times == 2) { Nov = i; break; }
        }
        times = 0;
        for (int i = 1; i <= 30; i++)
        {
            if (!day(y, 11, i)) times++;
            if (times == 2) { Mar = i; break; }
        }

        printf("Case #%d: ", ca);

        if (m > 3 && m < 11) printf("PDT");
        if (m > 11 || m < 3) printf("PST");
        if (m == 3)
        {
            if (h >= 3) printf("PDT");
                else if (h < 2) printf("PST");
                else printf("Neither");
        }
        else if (m == 11)
        {
            if (h >= 2) printf("PST");
                else if (h < 1) printf("PDT");
                else printf("Both");
        }
        printf("\n");


    }
}

  

 

posted @ 2018-10-02 18:31  jvruodejrLS  阅读(405)  评论(2编辑  收藏  举报

Contact with me