2019/1/28 模拟测试

昨天晚上的模拟测试QAQ


T1 :

“六.一”儿童节“文具套装”优惠销售,三种购买方式如下:

1、现购:10元/套,超过2套之外的,9元/套,超过10套之外的,则7.5元/套;

2、网购:9元/套,超过10套,全部打8折,超过50套,则全部打6折

3、团购:10套起团购,6元/套,达到或超过50套,则5元/套,达到或超过100套,则4元/套

【输入】购买方式号(1、2、3) 套数n(n <= 200)

【输出】应付钱数(保留2位小数)

【样例】输入:1 11 输出:99.50

不用多说了吧……水题一道

结果测试时脑抽写挂了(85pts)

于是就有了如下的代码(代码里第三种情况的判断,脑抽了):

#include <cstdio>

int main() {
    FILE *fin, *fout;
    fin = fopen("ta.in", "r");
    fout = fopen("ta.out", "w");
    int w, n;
    fscanf(fin, "%d%d", &w, &n);
    if(w == 1) {
        double sum = 0.0;
        if(n > 10) sum += (n - 10) * 7.5, n = 10;
        // cerr << sum << endl;
        if(n > 2) sum += (n - 2) * 9, n = 2;
        // cerr << sum << endl;
        sum += n * 10;
        // cerr << sum << endl;
        fprintf(fout, "%.2lf", sum);
    } 
    if(w == 2) {
        double sum = 0.0;
        if(n > 50) {
            sum = n * 9 * 0.6;
        } else {
            if(n > 10) {
                sum = n * 9 * 0.8;
            } else {
                sum = n * 9;
            }
        }
        fprintf(fout, "%.2lf", sum);
    }
    if(w == 3) {
        double sum = 0.0;
        if(n < 10) {
            fprintf(fout, "60.00");
            return 0;
        }
        if(n >= 50) {
            sum = n * 5;
        } else {
            if(n >= 100) {
                sum = n * 4;
            } else {
                sum = n * 6;
            }
        }
        fprintf(fout, "%.2lf", sum);
    }
    fclose(fin); fclose(fout);
    return 0;
}

// I good vegetable!

T2:

小明和小朋友们共同献爱心捐赠的图书共n类,每类m本。现在要讲这些书全部分给各个希望小学,规定:分给每个希望小学的书数量相同,种类k尽量多,并且每类书数量=k。

小明请你算算共能捐赠多少个希望小学?

【输入】n m (n,m<=10000) 【输出】XueXiao= 学校数

【样例】输入:12 54

输出:XueXiao=18

数据较小……

我们可以看到k<=n,所以枚举就行了qaq

但是如果数据大一点儿(long long范围),这种方法是不可过的

我们再来看一下,k是要同时被n和m整除的。

题目又要求k最大,很容易让人想到k=gcd(n,m)

不过由于我太菜了,所以用的暴力枚举

代码:

#include <cstdio>

int main() {
    FILE *fin, *fout ;
    fin = fopen("tb.in", "r");
    fout = fopen("tb.out", "w");
    int n, m, ans = -1;
    fscanf(fin, "%d%d", &n, &m);
    for(int i = n; i ; i--) {
        if(m < i) continue;
        if(n % i) continue;
        if(m % i) continue;
        ans = (n / i) * (m / i); break;
    }
    if(ans == -1) fprintf(fout, "Orz");
    else fprintf(fout, "XueXiao=%d", ans);
    fclose(fin); fclose(fout);
    return 0;
}

// bcku1 AK IOI !

T3:

梦幻王国钱币面值有5中:1、7、49、343、2401(即:\(7^0\)\(7^1\)\(7^2\)\(7^3\)\(7^4\))。某人买东西要用现金支付n元,买卖双方可以互相找钱(假设双方各种钱币数量都足够多)。

问:买卖双方最少供需用多少张钱币?

【输入】n (n<=30000) 【输出】最小钱币数

【样例】 输入:12 输出:4 (即:买方用2张7元,卖方找2张1元)

dp吧……

f[i]表示付i元钱最少要多少张钱币

枚举卖方要找的钱(显然,大于等于0,小于n),答案=min{f[i], f[i+n]}(卖方找的钱需要的纸币数量+买方需要的纸币数)

应该还有转成7进制的做法,可惜我太弱了不会

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

using namespace std;

int main() {
    FILE *fin, *fout;
    fin = fopen("tc.in", "r");
    fout = fopen("tc.out", "w");
    int n;
    fscanf(fin, "%d", &n);
    int f[60010];
    memset(f, 0x3f, sizeof(f));
    f[0] = 0;
    for(int i = 1; i <= (n << 1); i++) {
        f[i] = f[i - 1] + 1;
        if(i >= 7) f[i] = min(f[i], f[i - 7] + 1);
        if(i >= 49) f[i] = min(f[i], f[i - 49] + 1);
        if(i >= 343) f[i] = min(f[i], f[i - 343] + 1);
        if(i >= 2401) f[i] = min(f[i], f[i - 2401] + 1);
    }
    int ans = 0x7fffffff;
    for(int i = 0; i < n; i++) {
        ans = min(ans, f[i] + f[n + i]);
    }
    fprintf(fout, "%d", ans);
    fclose(fin); fclose(fout);
    return 0;
}

// AC_OIer AK IOI && AHOI !

T4:

长跑接力赛全程m公里,规定:每个队5人,每个人都必须跑而且只能跑一次,并且至少跑1公里,最多跑n公里,接力点必须在整公里处。刘教练挑选了5名队员,测试后得到每个人连续跑1、2、3、……、n公里的最短时间。他准备精心安排每个队员跑的公里数,使全队完成接力赛用时最短。你能帮教练做一个最佳方案吗?(数据保证最佳方案唯一)

(设:每个人连续跑的路程越长速度越慢,若有保持速度的,也绝不会变快。)

【输入】m n (m <= 5000, n <= 1000)

下接5行,每行n个整数(表示每人连续跑1~n公里的最短时间,以空格相隔)

【输出】第一行:最短时间(时间<=maxlongint)

第二行:五个整数(表示安排1~5号队员格子连续跑的公里数,以空格相隔)

【样例】 输入:25 10

333 700 1200 1710 2240 2613 3245 3956 4778 5899

300 610 960 1370 1800 2712 3834 4834 5998 7682

298 612 990 1560 2109 2896 3790 4747 5996 7654

289 577 890 1381 1976 2734 3876 5678 6890 9876

312 633 995 1467 1845 2634 3636 4812 5999 8123

输出:9748

6 5 5 4 5

正解是dp,然而我并不会做(膜拜综应班神仙写DP,不过90分)

当时想到了DP,结果算空间复杂度会MLE

而且卡在了输出方案上

灵(nao)光(zi)一(chou)下(le),把这道题写成了最小费用最大流(容量为每个人跑的公里,费用为时间)

把5名队员当做5个点,把1~n公里当成n个点。

每名队员向每个公里连一条容量为1,花费为多跑一公里所需要的时间(差分给出的时间)

建立超级源点,向5名队员分别连一条容量为n(每人最多n公里),费用为0的边

建立超级汇点,n个时间分别向超级汇点连一条容量为m,费用为0的边

这样的最大流是5*n,然而我们需要的流为m

于是我们把超级汇点再向另一个点连一条容量为m,费用为0的边,限制流量

最后的方案——每个人需要跑的公里数,就等于超级源点分配给五名队员的流量

这样做的话,有时会出现一个人一公里都没跑的情况,需要预处理

代码里把源点向队员连的边的费用设为1,为了防止分配流量过多的情况,最小费用减去m,不过这样做是多余的233(因为算法的原理)

没想到竟然A了

code :

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

using namespace std;

const int maxn = 1020;

struct edge {
    int t, next, cap, cost;
}e[12200]; 

int n, m, s, t1, t2, head[maxn], p = -1, t[maxn], mincost, vis[maxn], dis[maxn], pre[maxn], maxflow;

void add_edge(int s, int t, int cap, int cost) {
    p++; 
    e[p].t = t;
    e[p].cap = cap;
    e[p].cost = cost;
    e[p].next = head[s];
    head[s] = p;
}

bool spfa() {
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i <= maxn; i++) {
        dis[i] = 0x7fffffff;
    }
    queue < int > q;
    q.push(s);
    dis[s] = 0; vis[s] = 1;
    while(!q.empty()) {
        int k = q.front();
        // cerr << k << endl;
        q.pop();
        vis[k] = false;
        for(int i = head[k]; i != -1; i = e[i].next) {
            // cerr << i << " ";
            if(e[i].cap > 0 && dis[e[i].t] - dis[k] > e[i].cost) {
                dis[e[i].t] = dis[k] + e[i].cost;
                pre[e[i].t] = i;
                if(!vis[e[i].t]) {
                    vis[e[i].t] = 1;
                    q.push(e[i].t);
                }
            }
        }
        // cerr << endl << "==========" << endl;
    }
    // cerr << dis[t2] << endl; 
    if(dis[t2] == 0x7fffffff) return false;
    else return true;
}

void MCMF() {
    while(spfa()) {
        int qwq = t2;
        int flow = 0x7fffffff;
        while(qwq != s) {
            // cerr << qwq << " ";
            flow = min(flow, e[pre[qwq]].cap);
            qwq = e[pre[qwq] ^ 1].t;
        }
        // cerr << endl;
        // if(flow == 0) break;
        qwq = t2;
        while(qwq != s) {
            e[pre[qwq]].cap -= flow;
            e[pre[qwq] ^ 1].cap += flow;
            qwq = e[pre[qwq] ^ 1].t;
        }
        mincost += flow * dis[t2];
        maxflow += flow;
    }
}

int main() {
    FILE *fin, *fout;
    fin = fopen("td.in", "r");
    fout = fopen("td.out", "w");
    s = 0, t1 = maxn - 3, t2 = maxn - 2;
    fscanf(fin, "%d%d", &m, &n);
    memset(head, -1, sizeof(head));
    mincost = -m;
    for(int i = 1; i <= 5; i++) {
        add_edge(s, i, n, 1);
        add_edge(i, s, 0, -1);
    }
    for(int i = 1; i <= 5; i++) {
        fscanf(fin, "%d", &t[1]);
        mincost += t[1];
        for(int j = 2; j <= n; j++) {
            fscanf(fin, "%d", &t[j]);
            add_edge(i, j + 5, 1, t[j] - t[j - 1]);
            add_edge(j + 5, i, 0, t[j - 1] - t[j]); 
        }
    }
    for(int i = 1; i <= n; i++) {
        add_edge(i + 5, t1, m, 0);
        add_edge(t1, i + 5, 0, 0);
    }
    add_edge(t1, t2, m - 5, 0);
    add_edge(t2, t1, 0, 0);
    MCMF();
    if(maxflow < m - 5) fprintf(fout, "%d\n", 0x7fffffff);
    else fprintf(fout, "%d\n", mincost + 5);
    int ans[10];
    for(int i = head[s]; i != -1; i = e[i].next) {
        ans[e[i].t] = n - e[i].cap + 1;
    }
    for(int i = 1; i <= 5; i++) {
        fprintf(fout, "%d ", ans[i]);
    }
    fclose(fin); fclose(fout);
    return 0;
}

拿了385pts,rk1,qaq

总结:

  1. 我是真的菜

  2. 本以为bcku1能AK的,没料到我拿了rk1……只能说班里的神仙都不屑于认真打码了qaq

猜你喜欢

转载自www.cnblogs.com/iycc/p/10330232.html