CCPC 2016-2017, Finals

A - The Third Cup is Free

HDU - 5999

题意:每买三杯饮料,最便宜的一杯免费。签到题
AC代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];

bool cmp(int a, int b) {
    return a > b;
}

int main() {
    int T, n;
    int kase = 0;
    int ans = 0;
    scanf("%d", &T);
    while(T--) {
        scanf("%d",&n);
        ans = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            ans += a[i];
        }
        sort(a+1, a+n+1, cmp);
        for(int i = 1; i <= n; i++) {
            if(i%3 == 0)
                ans -= a[i];
        }
        printf("Case #%d: %d\n", ++kase, ans);
    }
    return 0;
}

B - Wash

HDU - 6000

题意:有L件衣服,n台洗衣机,m台烘干机,每台洗衣机的工作时间为W1,W2,...,Wn,烘干机的工作时间为D1,D2,...,Dn,问洗完这些衣服需要的最短时间。
∙1≤T≤100
∙1≤L≤1e6
∙1≤N,M≤1e5
∙1≤Wi,Di≤1e9
思路:贪心,但赛场上愣是没想出来。洗衣机的工作时间比较好贪,用一个优先队列,每次取工作时间最短的洗衣机,然后将洗衣机的结束时间 += 工作时间再压回队列即可。主要是对烘干机的处理,这里应该是让结束洗衣时间越晚的衣服尽量用快的烘干机,这样时间一长+一短,才能够使得总时间尽量的短。所以我们在这里倒序处理每件衣服的烘干。
AC代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e6+10;

struct node {
    ll time, endtime;
    friend bool operator < (node a, node b) {
        return a.endtime > b.endtime;
    }
};
ll ans[maxn];

int main() {
    int T, l, n, m;
    ll t;
    int kase = 0;
    scanf("%d", &T);
    while(T--) {
        priority_queue<node> que1, que2;
        scanf("%d%d%d", &l, &n, &m);
        for(int i = 0; i < n; i++) {
            scanf("%lld", &t);
            que1.push((node){t,t});
        }
        for(int j = 0; j < m; j++) {
            scanf("%lld", &t);
            que2.push((node){t,t});
        }
        node temp;
        for(int i = 1; i <= l; i++) {
            temp = que1.top();
            que1.pop();
            ans[i] = temp.endtime;
            temp.endtime += temp.time;
            que1.push(temp);
        }
        ll endans = 0;
        for(int i = l; i >= 1; i--) {
            temp = que2.top();
            que2.pop();
            endans = max(endans, temp.endtime + ans[i]);
            temp.endtime += temp.time;
            que2.push(temp);
        }
        printf("Case #%d: %lld\n", ++kase, endans);
    }
    return 0;
}

C - Mr.Panda and Survey

HDU - 6001

D - Game Leader

HDU - 6002

题意:给出社交网络中Tom的朋友排行榜(Tom)也在排行榜中。排行榜是按照每个人的评分排序的。给出的排行中的数字是该人在C[i]个榜单上占据第一。同时给出m组朋友关系,表示这两个人是朋友,当然也有一些朋友关系是Tom不知道的。问有最少有多少个陌生人的榜一是Tom的朋友。
思路:优先队列贪心。贪了很久没贪明白……待补。

E - Problem Buyer

HDU - 6003

题意:给出n个区间,m个数,让你任意选k个数,使一定能包含这m个数,一个区间只能包含一个数 求最小的k
思路:据说是个肥肠难想的贪心……待补。

F - Periodical Cicadas

HDU - 6004

G - Pandaland

HDU - 6005

题意:给你一个m 个边的无向图,要求在图上找一个边权之和最小的环
思路:dijkstra暴力+剪枝。由于最小环肯定会包含某一条边,那么我们可以通过枚举每条边,以边的两个端点为s和t,令这条边的权为INF,跑dijkstra,那么跑出来的 d[t] 加上这条边初始的边权即为包含该边的最小环权值。每次跑完取最小值即可。
预处理把坐标离散化。注意判最后若ans =INF,直接改为ans = 0。
剪枝:如果优先队列中最小边权 + 被枚举的边的初始边权 >= ans,可以直接break掉。
AC代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
using namespace std;

const int maxn = 4000 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef pair<int, int> pr;
int d[2*maxn];
map<pr, int> mp;
int ans;
int cnt;
int s, t;

struct edge { int to, cost; };
struct edge2 { int ID1, ID2, cost; }e[maxn];
vector<edge> g[maxn];

int getid(pr p) {
    if(!mp[p])  mp[p] = ++cnt;
    return mp[p];
}

void dijkstra(int s, int cst) {
    priority_queue<pr, vector<pr>, greater<pr> > que;
    for(int i = 1; i <= cnt; i++)
        d[i] = INF;
    d[s] = 0;
    que.push(make_pair(0,s));
    while(!que.empty()) {
        pr now = que.top();
        que.pop();
        int u = now.second;
        if(now.first + cst >= ans) break;
        if(d[u] < now.first)
            continue;
        for(int i = 0; i < (int)g[u].size(); ++i) {
            edge edg = g[u][i];
            int v = g[u][i].to;
            if( u == s && v == t )
                edg.cost = INF;
            if( d[u] + edg.cost < d[v]) {
                d[v] = d[u] + edg.cost;
                que.push(make_pair(d[v], v));
            }
        }
    }
}

void init() {
    for(int i = 1; i <= cnt; i++)
        g[i].clear();
    mp.clear();
    cnt = 0;
}

int main() {
    int T, m;
    int kase = 0;
    scanf("%d", &T);
    int x1, y1, x2, y2, cost, id1, id2;
    while(T--) {
        init();
        scanf("%d", &m);
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &cost);
            id1 = getid(make_pair(x1, y1));
            id2 = getid(make_pair(x2, y2));
            e[i] = (edge2){id1, id2, cost};
            g[id1].push_back((edge){id2, cost});
            g[id2].push_back((edge){id1, cost});
        }
        /*
        map<pr, int>::iterator it = mp.begin();
        for( ; it != mp.end(); ++it)
            cout << it->first.first << " " << it->first.second << " " << it->second << endl;
        */
        ans = INF;
        for(int i = 0; i < m; i++) {
            s = e[i].ID1, t = e[i].ID2;
            dijkstra(s, e[i].cost);
            //cout << d[t] << endl;
            ans = min(ans, d[t] + e[i].cost);
        }
        if(ans >= INF) ans = 0;
        printf("Case #%d: %d\n", ++kase, ans);
    }
    return 0;
}

H - Engineer Assignment

HDU - 6006

题意:有n项工作,m个雇员。每一项工作涉及到C[i] ( 1 ≤ C[i] ≤ 3 )个领域,每个人擅长D[i] ( 1 ≤ D[i] ≤ 3 )个领域,领域由1~100的编号表示。
思路:比赛的时候感觉是匹配,但是建不出图来,比较奇妙的是C[i]和D[i]都惊人的小。赛后查了一下居然是状压dp……

I - Mr. Panda and Crystal

HDU - 6007

题意:岛上有n种宝石,有的宝石可以用魔力值合成,有的宝石不可以用魔力值合成。还有k种配方,即由几种宝石合成另一种。每一种宝石都有一个售价。现在,Panda有m的魔力值,问Panda得到的宝石最多能卖出多少钱。
思路:可以通过配方用消耗魔力值低的宝石去合成消耗魔力值低或者不能够用魔力值合成但是售价高的宝石,只要能够知道每个宝石最少需要多少魔力值合成,就可以将模型转化为物品重量为最低魔力值,价值为宝石售价,容量为m的完全背包。比赛的时候开这个题开的太晚了,只剩不到一个小时,所以没想清楚关于计算每个宝石合成所需要的“最低魔力值”如何计算,曾经想过跑最短路,但是当时没想清楚怎么建图。dijkstra处理出来之后,就是非常水的完全背包了。
注意每个宝石消耗的魔力值c[i]不能够初始化为INF,因为有的宝石可能最终也无法由任何方式合成,因此RE了好几次。其实直接把一开始无法用魔力之合成的宝石c[i]定义为m+1就可以了。
AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
const int maxn = 210;
const int INF = 0x3f3f3f3f;
int c[maxn], w[maxn];
int dp[10010];
vector<int> g[maxn];
bool vis[maxn];
int m, n, k;

struct node {
    int to, cost;
    bool operator < (const node n_) const {
        return cost > n_.cost;
    }
};

priority_queue<node> que;

struct node2 {
    int goal;
    vector<pair<int, int> > vec;
}e[maxn];

void check() {
    puts("------------\n");
    for(int i = 1; i <= n; i++)
        printf("%d %d\n", i, c[i]);
    puts("\n------------");
}

int getsum(node2& nd) {
    int sum = 0;
    for(int i = 0; i < nd.vec.size(); i++) {
        sum += nd.vec[i].second * c[nd.vec[i].first];
    }
    return sum;
}

void dijkstra() {
    int u, newcost;
    while(!que.empty()) {
        node nd = que.top();
        que.pop();
        u = nd.to;
        if(vis[u])  continue;
        vis[u] = true;
        for(int i = 0; i < (int)g[u].size(); i++) {
            node2& nd2 = e[g[u][i]];
            newcost = getsum(nd2);
            if(newcost < c[nd2.goal]) {
                c[nd2.goal] = newcost;
                que.push((node){nd2.goal, c[nd2.goal]});
            }
        }
    }
}

void init() {
    memset(vis, 0, sizeof vis);
    memset(dp, 0, sizeof dp);
}

int main()
{
    int T;
    int kase = 0;
    scanf("%d", &T);
    while(T--) {
        init();
        scanf("%d%d%d", &m, &n, &k);
        int flag;
        for(int i = 1; i <= n; i++) {
            g[i].clear();
            scanf("%d", &flag);
            if(flag) {
                scanf("%d", &c[i]);
                que.push((node){i, c[i]});
            }
            else {
                c[i] = m+1;
            }
            scanf("%d", &w[i]);
        }
        int sum_, type_, num_;
        for(int i = 0; i < k; i++) {
            scanf("%d%d", &e[i].goal, &sum_);
            e[i].vec.clear();
            for(int j = 0; j < sum_; j++) {
                scanf("%d%d", &type_, &num_);
                e[i].vec.push_back(make_pair(type_, num_));
                g[type_].push_back(i);
            }
        }
        
        dijkstra();
        //check();
        for(int i = 1; i <= n; i++) {
            for(int v = c[i]; v <= m; v++) {
                dp[v] = max(dp[v], dp[v-c[i]]+w[i]);
            }
        }
        printf("Case #%d: %d\n", ++kase, dp[m]);
    }
    return 0;
}

J - Worried School

HDU - 6008

思路:据说是个模拟,队友A的
AC代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <queue>
#include <string>
#include <set>

using namespace std;

int n;
string str, s;
queue<string> q[6];
set<string> st;

int cal() {
    st.clear();
    int m = 0;

    for(int i = 0; i < 100; ++i) {
        if(q[i % 5].front() == str)
            return n - m;
        if(st.find(q[i % 5].front()) == st.end()) {
            ++m;
            st.insert(q[i % 5].front());

            if(m == n)
                return 0;
        }
        q[i % 5].pop();
    }
    return 0;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);

    int T, t = 0;
    cin >> T;
    while(T--) {
        for(int i = 0; i < 6; ++i) {
            while(!q[i].empty())
                q[i].pop();
        }

        cin >> n >> str;

        for(int i = 0; i < 6; ++i) {
            for(int j = 0; j < 20; ++j) {
                cin >> s;
                q[i].push(s);
            }
        }

        int ans = cal(), i = 0;

        while(!q[5].empty() && i < ans) {
            if(q[5].front() == str) {
                ans = -1;
                break;
            }
            if(st.find(q[5].front()) == st.end()) {
                st.insert(q[5].front());
                ++i;
            }
            q[5].pop();
        }
        cout << "Case #" << ++t << ": ";
        if(ans == -1)
            cout << "ADVANCED!" << endl;
        else
            cout << ans << endl;
    }
    return 0;
}

K - Lazors

HDU - 6009

L - Daylight Saving Time

HDU - 6010

题意:有关夏令时。每年3月份的第2个星期天的2:00会跃变为3:00,同时标准时从PST变为PDT;每年11月份的第1个星期天的2:00会跃变为1:00,同时标准时从PDT变为PST;现在给出一个介于“2007-01-01 00:00:00” 和 “2100-12-31 23:59:59”的时间点,判断这个时间点是PDT/PST/Both/Neither。
思路:对于在三月份和十一月份的日子,用基姆拉尔森公式算一下这一天是星期几,如果在变动夏令时的这一天的话具体判断一下时间,其他的直接找PST/PDT。比较坑的是3月第2个星期天的[2:00,3:00)属于Neither,11月份第1个星期天的[1:00,2:00)是Both,至于这个半闭半开区间,没读出来,有点迷,交了两发wa猜的那个边界。感觉四级要gg。
AC代码

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
using namespace std;

int weekday(int y, int m, int d) {
    if(m == 1 || m == 2) {
        m += 12;
        y--;
    }
    int w = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
    return w;//0->monday
}

int main() {
    int T;
    scanf("%d", &T);
    int kase = 0;
    int flag = 0;
    //1:pst, 2:pdt, 3:both, 4:neither;
    int year, month, date, hour, minute, second;
    while(T--) {
        scanf("%d-%d-%d %d:%d:%d",&year, &month, &date, &hour, &minute, &second);
        if(month == 3) {
            int i;
            int cnt = 0;
            for(i = 1; i <= 31; i++) {
                if(weekday(year, month, i) == 6) {
                    cnt++;
                    if(cnt == 2)
                        break;
                }
            }
            if(date==i) {
                if(hour<2)  flag = 1; //pst
                else if(hour >= 3)  flag = 2; //pdt
                else    flag = 4;  //neither
            }
            else if(date < i) flag = 1; //pst
            else flag = 2; //pdt;
        }
        else if(month == 11) {
            int i;
            for(i = 1; i <= 30; i++) {
                if(weekday(year, month, i) == 6)
                    break;
            }
            if(date==i) {
                if(hour<1)  flag = 2; //pdt
                else if(hour >= 2)  flag = 1; //pst
                else flag = 3;  //both
            }
            else if(date < i) flag = 2; //pdt
            else flag = 1; //pst
        }
        else if(month > 3 && month < 11)    flag = 2; //pdt
        else  flag = 1; //pst

        printf("Case #%d: ", ++kase);
        if(flag == 1) printf("PST\n");
        else if(flag == 2)  printf("PDT\n");
        else if(flag == 3)  printf("Both\n");
        else if(flag == 4)  printf("Neither\n");
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容