CCPC 2016-2017, Finals

A - The Third Cup is Free

HDU - 5999

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

#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
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 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 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

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

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

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

void dijkstra(int s, int cst) {
    priority_queue, greater > 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::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 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 210;
const int INF = 0x3f3f3f3f;
int c[maxn], w[maxn];
int dp[10010];
vector 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 que;

struct node2 {
    int goal;
    vector > 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int n;
string str, s;
queue q[6];
set 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 
#include 
#include 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(CCPC 2016-2017, Finals)