CCPC 2016 Final 【solve 6 of 12】

按难度排序:

A.The Third Cup is Free【简单贪心】

题意:
有n杯咖啡,每杯有对应的价格。每三杯可免费其中最便宜的一杯。求购买n杯咖啡的最小花费。
做法:
从大到小排序,每三杯累计前两杯的费用。
代码:

#include <bits/stdc++.h>
using namespace std;
int a[100100];
inline int rd(){
    int x = 0,f = 1;
    char ch=getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
int main() {
    int T;
    T = rd();
    for(int cas = 1; cas <= T; ++ cas) {
        int n;
        n = rd();
        int sum = 0;
        for(int i = 0; i < n; ++ i)
            a[i] = rd(), sum += a[i];
        sort(a, a + n, greater<int>());
        int tmp = 0;
        for(int i = 2; i < n; i += 3)
            tmp += a[i];
        printf("Case #%d: %d\n", cas, sum - tmp);
    }
    return 0;
}

大量输入,开挂对比。
开挂对比

J - Worried School【模拟】

题意:
1.晋级Final有G个名额,分为X和Y,G = X + Y,一个学校至多一个名额。
2.X为区域赛。输入给你5场区域赛的前20名。名额分配顺序:A1,B1,C1,D1,E1,A2,B2….E20,若该学校已经有名额了,直接跳过。
3.Y为EC-FINAL。输入给你该场比赛的前20名。
4.给你一个学校名称和G的大小。问你该学校能否一定进FINAL。
5.一定能进输出ADVANCED!否则输出最小的Y。
做法:
1.按顺序扫5场区域赛,扫到该学校则停止,设此时已经有A个学校进FINAL了。
2.如果此时A >= G,那么直接输出0,即所有FINAL名额均有区域赛所得。
3.否则,继续扫EC-FINAL,总共扫B(B=G-A)个,如果该学校出现在在这前B个中,那么就是ADVANCED,不然输出B。(代码稍微不同,但同个道理)
4.所有扫描要跳过已进决赛的学校,扔set里find就行。
代码:

#include <bits/stdc++.h>
using namespace std;
string scf() {
    char s[7];
    scanf("%s", s);
    return s;
}
string name[6][20];
set<string>st;
int main() {
    int T, n;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; cas++) {
        st.clear();
        scanf("%d", &n);
        string fi = scf();
        for(int i = 0; i < 6; ++ i) {
            for(int j = 0; j < 20; ++ j) {
                name[i][j] = scf();
            }
        }
        bool f = true;
        for(int i = 0; i < 20; ++ i) {
            for(int j = 0; j < 5; ++ j) {
                if(name[j][i] == fi) {
                    f = false;
                    break;
                } else {
                    st.insert(name[j][i]);
                }
            }
            if(f == false) break;
        }
        printf("Case #%d: ", cas);
        if((int)st.size() >= n) puts("0");
        else {
            int ans = n - st.size();
            for(int i = 0; i < 20; ++ i) {
                if(name[5][i] == fi) break;
                st.insert(name[5][i]);
            }
            if((int)st.size() >= n) printf("%d\n", ans);
            else puts("ADVANCED!");
        }
    }
}

L. Daylight Saving Time【模拟、瞎搞】

题意:
1.给你PST和PDT的定义。然后给你个时间,判断是PST or PDT or Both or Neither.
2.定义:
PST -> PDT:每年03月第2个星期天(2点->3点)。
PDT -> PST:每年12月第1个星期天(2点->1点)。
原文:the local time changes from Pacific Standard Time (PST) to Pacific Daylight Time (PDT) at 02:00 to 03:00 on the second Sunday in March and the local time changes back from PDT to PST at 02:00 to 01:00 on the first Sunday in November.
做法:
1.自己根据题意画出一年的区间,然后判断哪个区间属于哪个答案。
2.抄模板判断3月第2个星期天日期,或者12月第1个星期天日期。
3.不属于这2天的好判断,属于的话,通过计算权重来比较时间先后,从而得出结果。
代码:

#include <bits/stdc++.h>
using namespace std;
int wd(int d, int m, int y) {
    int ans;
    if(m == 1 || m == 2)
        m += 12, y--;
    if((y < 1752) || (y == 1752 && m < 9) || (y == 1752 && m == 9 && d < 3))
        ans = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 + 5) % 7;
    else
        ans = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
    return ans + 1;
}
int main() {
    int d, m, y, h, mi, s, T;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; ++ cas) {
        scanf("%d-%d-%d %d:%d:%d", &y, &m, &d, &h, &mi, &s);
        printf("Case #%d: ", cas);
        int time = h * 3600 + mi * 60 + s;
        int d11, d3, cnt = 0;
        for(int i = 1; i <= 31; ++ i) {
            if(wd(i, 3, y) == 7) cnt++, d3 = i;
            if(cnt == 2) break;
        }
        for(int i = 1; i <= 31; ++ i) {
            if(wd(i, 11, y) == 7) {
                d11 = i;
                break;
            }
        }
        long long cmp3 = 1LL * y * 12 + 3 * 31 + d3;
        long long cmp11 = 1LL * y * 12 + 11 * 31 + d11;
        long long cur = 1LL * y * 12 + m * 31 + d;
        if(cur < cmp3 || cur > cmp11) puts("PST");
        else if(cur > cmp3 && cur < cmp11) puts("PDT");
        else if(cur == cmp3) {
            int cmp2 = 7200, cmp3 = 10800;
            int curr = 3600 * h + 60 * mi + s;
            if(curr < cmp2) puts("PST");
            else if(curr >= cmp2 && curr < cmp3) puts("Neither");
            else puts("PDT");
        } else if(cur == cmp11) {
            int cmp1 = 3600, cmp2 = 7200;
            int curr = 3600 * h + 60 * mi + s;
            if(curr < cmp1) puts("PDT");
            else if(curr >= cmp1 && curr < cmp2) puts("Both");
            else puts("PST");
        }
    }
}

B - Wash【贪心】

PS:
题意很好理解,贪心思路最近自己想到了。但是去年太太菜了啊,当时只要过了这题就能拿牌,可惜了。
题意:
你有L件衣服要洗。你有N个洗衣机,和M个烘干机。然后给你N个洗衣机的工作时间,还有M个烘干机工作时间。机器每次只能处理一件衣服,但可以多次使用。
数据范围:
1L106 1N,M105 1Wi,Di109
做法:
1.洗和烘干并不冲突,可以分开考虑。
2.洗的部分,用优先队列维护完成时刻距离开始的时间t。
1)先将初始所有洗衣机扔进队列
2)每次弹出最小时间,记录下,然后将工作完的时刻继续扔进队列(例如工作时间为2,第一次弹出2, 再扔进去4。所以需要两个参数,一个是当前时刻x,一个是工作时间base,每次再扔一个base + x进队)
3)总共弹出L个,即是最优的洗衣方案。
3.烘干部分同理。
4.关键问题在于,如何将烘干部分和洗的部分结合起来。为了让总时间最小,所以一定是(洗的越小+烘的越大),这样的策略是最优的,不难证明,略。
5.大+小,维护最大值,就是结果。
代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 10;
struct Node {
    LL x, base;
    Node(){}
    Node(LL xx, LL basee) : x(xx), base(basee) {}
    bool operator < (const Node &o) const {
        return x > o.x;
    }
};
inline int rd(){
    int x = 0,f = 1;
    char ch=getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
priority_queue<Node>q1, q2;
LL cost[maxn];
int main() {
    int T;
    T = rd();
    for(int cas = 1; cas <= T; ++ cas) {
        int l, n, m, x;
        while(!q1.empty()) q1.pop();
        while(!q2.empty()) q2.pop();
        l = rd(), n = rd(), m = rd();
        for(int i = 0; i < n; ++ i)
            x = rd(), q1.push(Node(x, x));
        for(int i = 0; i < m; ++ i)
            x = rd(), q2.push(Node(x, x));
        for(int i = 1; i <= l; ++ i) {
            Node top = q1.top(); q1.pop();
            cost[i] = top.x;
            top.x += top.base;
            q1.push(top);
        }
        LL ans = 0;
        for(int i = l; i >= 1; -- i) {
            Node top = q2.top(); q2.pop();
            ans = max(ans, cost[i] + top.x);
            top.x += top.base;
            q2.push(top);
        }
        printf("Case #%d: %lld\n", cas, ans);
    }
}

H - Engineer Assignment【状压DP】

题意:
做法:
代码:

#include <bits/stdc++.h>
using namespace std;
int dp[20][1 << 11];
int mp[110];
vector<int>v[20];
vector<int>Proj[20], wor[20];
void init() {
    memset(dp, 0, sizeof(dp));
    memset(mp, 0, sizeof(mp));
    for(int i = 0; i < 20; ++ i) {
        v[i].clear();
        Proj[i].clear();
        wor[i].clear();
    }
}
int main() {
    int T;
//    freopen("in.txt", "r", stdin);
    scanf("%d", &T);
    for(int cas = 1; cas <= T; ++ cas) {
        int n, m, x, y;
        init();
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; ++ i) {
            scanf("%d", &x);
            for(int j = 0; j < x; ++ j) {
                scanf("%d", &y);
                Proj[i].push_back(y);
            }
        }
        for(int i = 0; i < m; ++ i) {
            scanf("%d", &x);
            for(int j = 0; j < x; ++ j) {
                scanf("%d", &y);
                wor[i].push_back(y);
            }
        }
        for(int i = 0; i < n; ++ i) {
            for(int st = 0; st < (1 << m); ++ st) {
                memset(mp, 0, sizeof(mp));
                int cnt = 0;
                for(int j = 0; j < m; ++ j) {
                    if(st & (1 << j)) {
                        cnt ++;
                        for(int k = 0; k < wor[j].size(); ++ k) {
                            mp[wor[j][k]]++;
                        }
                    }
                }
                if(cnt > 3) continue;
                bool f = true;
                for(int j = 0; j < Proj[i].size(); ++ j) {
                    if(mp[Proj[i][j]] == 0) f = false;
                }
                if(f == true) v[i].push_back(st);
            }
        }
//        for(int i = 0; i < n; ++ i) {
//            for(int j = 0; j < v[i].size(); ++ j) {
//                cout << v[i][j] << ' ';
//            }
//            cout << endl;
//        }
        for(int st = 0; st < (1 << m); ++ st) {
            for(int j = 0; j < v[0].size(); ++ j) {
                if((st | v[0][j]) == st)
                    dp[0][st] = 1;
            }
        }
        for(int i = 1; i < n; ++ i) {
            for(int st = 0; st < (1 << m); ++ st) {
                for(int j = 0; j < v[i].size(); ++ j) {
                    if((st | v[i][j]) == st) {
                        dp[i][st] = max(dp[i][st], dp[i - 1][st - v[i][j]] + 1);
                    }
                }
                dp[i][st] = max(dp[i][st], dp[i - 1][st]);
            }
        }
        printf("Case #%d: %d\n", cas, dp[n - 1][(1 << m) - 1]);
    }
}

I - Mr. Panda and Crystal【dijstra+背包】

题意:
做法:
代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
const int maxn =210;
vector<pii>p[maxn],G[maxn];
int dist[maxn], val[maxn];
bool vis[maxn];
int m, n, k, op;
priority_queue<pii,vector<pii>, greater<pii> >q;
void dij()
{
    while(!q.empty()) q.pop();
    for(int i = 1; i <= n; ++ i) {
        if(dist[i] <= m) q.push(make_pair(dist[i], i));
    }
    memset(vis, false, sizeof(vis));
    while(!q.empty()) {
        int u = q.top().second; q.pop();
        if(vis[u]) continue;
        vis[u] = true;
        for(int i = 0; i < G[u].size(); ++ i) {
            int v = G[u][i].second, h = G[u][i].first;
            if(vis[v]) continue;
            int sum = 0;
            for(int j = 0; j < p[h].size(); ++ j) {
                int x = p[h][j].first, y = p[h][j].second;
                sum += dist[x] * y;
            }
            if(sum < dist[v]) {
                dist[v] = sum;
                q.push(make_pair(dist[v],v));
            }
        }
    }
}
int dp[10100];
int main()
{
    int T;
    scanf("%d", &T);
    for(int cas = 1; cas <= T; ++ cas) {
        scanf("%d%d%d", &m, &n, &k);
        for(int i = 0; i <= max(k, n); ++ i)
            p[i].clear(), G[i].clear();
        for(int i = 1; i <= n; ++ i) {
            scanf("%d", &op);
            if(op == 0) {
                scanf("%d", &val[i]);
                dist[i] = m + 1;
            }
            else {
                scanf("%d%d", &dist[i], &val[i]);
            }
        }
        for(int i = 0; i < k; ++ i) {
            int x, y;
            scanf("%d%d", &x, &y);
            for(int j = 0; j < y; ++ j) {
                int u, v;
                scanf("%d%d", &u, &v);
                p[i].push_back(make_pair(u, v));
                G[u].push_back(make_pair(i, x));
            }
        }
        dij();
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; ++ i)
            for(int j = dist[i]; j <= m; ++ j)
                dp[j] = max(dp[j], dp[j - dist[i]] + val[i]);
        printf("Case #%d: %d\n", cas, dp[m]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值