1003考试

1003考试

T1

​ 题目大意:

​ 一支蜡烛可以燃烧一个小时,然后就会熄灭。如果你拥有𝑏支已经熄灭的蜡烛,你可以将它们做成一支新的蜡烛。最开始你有𝑎支蜡烛,你最多能让它们燃烧多久呢?

​ 太水了太水了,直接切。

#include <bits/stdc++.h>
    
using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}
    
long long a, b, ans, res, sum;

int main() {

    a = read(); b = read(); sum = a;
    ans = a;
    for(int i = 1; ; i++) {
        res = sum / b; ans += res;
        sum = res + sum % b;
        if(sum < b) break; 
    }
    printf("%lld", ans);

    fclose(stdin); fclose(stdout);
    return 0;
}

T2

​ 题目大意:

​ 现有𝑛支队伍进行循环赛(每两支队伍恰好比赛一场),胜者得3分,平局各得1分,负者不得分。给出这𝑛支队伍的最终总得分,求满足条件的方案数。(网上可以搜到原题)

​ 搜索 + 记忆化 + 剪枝。

​ 缩索的框架呢,就是一个格一个格的往里面填数,显然要填\(n *(n - 1) / 2\)个格子。

​ 可行性剪枝:判断当前行的sum如果大于这个球队的分数,直接返回;如果当前行的sum加上后面几场全部赢的分数还不能符合条件,那么也直接返回。我们还可以根据已有信息算出整个里面有几个胜场,几个平局,我们在搜的时候如果胜场或平局的个数大于这个,那么也直接返回。

​ 记忆化:当前行的填数方案确定了之后,我们把剩下几行搞个哈希,下次搜到相同的直接返回本次算出的值就好了。

#include <bits/stdc++.h>
    
using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}
    
const int N = 11, mod = 1e9 + 7;
int n, win, pin, sum;
int a[N], b[N], sum_hang[N];
map <long long, long long> mp;

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

int dfs(int x, int y) {
    if(x == n) return 1;
    if(sum_hang[x] + (n - y + 1) * 3 < a[x]) return 0;
    if(y == n + 1) {
        for(int i = x + 1;i <= n; i++) b[i] = a[i] - sum_hang[i];
        sort(b + x + 1, b + n + 1);
        long long res = 0;
        for(int i = x + 1;i <= n; i++) res = 1ll * res * 28 + b[i];
        if(mp.find(res) != mp.end()) return mp[res];
        else return mp[res] = dfs(x + 1, x + 2);
    }
    long long sum = 0;
    if(sum_hang[x] + 3 <= a[x] && win) { //赢
        sum_hang[x] += 3; win --;
        sum += dfs(x, y + 1);
        sum_hang[x] -= 3; win ++;
    }
    if(sum_hang[y] + 3 <= a[y] && win) { //输
        sum_hang[y] += 3; win --;
        sum += dfs(x, y + 1);
        sum_hang[y] -= 3; win ++;
    }
    if(sum_hang[x] + 1 <= a[x] && sum_hang[y] + 1 <= a[y] && pin) { //平局
        sum_hang[x] ++, sum_hang[y] ++; pin --;
        sum += dfs(x, y + 1);
        sum_hang[x] --, sum_hang[y] --; pin ++;
    }
    return sum % mod;
}

int main() {

    n = read();
    for(int i = 1;i <= n; i++) a[i] = read(), sum += a[i];
    win = sum - n * (n - 1);
    pin = n * (n - 1) / 2 - win;
    sort(a + 1, a + n + 1, cmp);
    printf("%d", dfs(1, 2) % mod);

    fclose(stdin); fclose(stdout);
    return 0;
}

T3

​ 题目大意:

​ 有𝑛个人想要坐车,线路可以抽象成一条数轴。第𝑖个人想要从坐标𝑠𝑖坐到坐标𝑡𝑖。你的车从原点0出发,最终行驶到坐标𝑚。车上最多只能同时坐一个乘客,但你可以让乘客中途下车,只需保证最终将其送达他的目的地即可。在满足所有人的需求下,你行驶的最小总路程是多少呢?

​ 这个题难死我了,暴力也不会打。

​ 我们把车走过的路程分为两部分,一部分是车上有人,一部分是没人。

​ 车上有人的很好求:\(\displaystyle \sum_{i = 1}^{n} abs(t[i] - s[i])\)

​ 现在我们要最小化车上没人的路程,当我们运送完某一个人时,我们找到一个最近的上车点肯定是最优的,因为如果有一个稍远一点的上车点,那还不如先把最近的这个人载一乘。(貌似这么解释会少一点情况,但就是这么贪心的走,路程就最小)

​ 所以现在只需把所以的\(s[i], t[i]\)排个序就好了,注意让\(s[0] = m, t[0] = 0\), 因为车要从0走到m。

​ 正解代码还是很少的:

#include <bits/stdc++.h>
    
using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5;    
int n, m;
int s[N], t[N];
long long ans;

int cmp(int a, int b) { return a < b; }

int main() {
    
    n = read(); m = read();
    for(int i = 1;i <= n; i++) s[i] = read(), t[i] = read(), ans += abs(t[i] - s[i]);
    s[0] = m, t[0] = 0;
    sort(s, s + n + 1, cmp);
    sort(t, t + n + 1, cmp);
    for(int i = 0;i <= n; i++) ans += abs(s[i] - t[i]);
    printf("%lld", ans);

    fclose(stdin); fclose(stdout);
    return 0;
}

T4

​ 题目大意:

​ 你参加了一次比赛,共有𝑛(奇数)个评委给你打分,编号为1到𝑛。你最终的得分通过如下方式得到:评委们按编号排成一排,每次取出前三名评委,留下其中评分的中位数并将其加入队尾,直到只剩最后一名评委,该评委的评分就是你最终的得分。现在你知道了所有评委的评分和部分评委的编号,你想要知道,对于剩余评委所有可能的编号情况中,你的得分最高能达到多少。

​ 二分答案。

​ 我们二分中位数的值,显然答案具有单调性。

​ 我们把原序列大于等于\(mid\)数赋为1,小于的赋为0。那么现在有一些位置不确定,但是我们可以知道这些位置总共1的个数是多少, 设这个个数为\(res\)

​ 设\(f[i]\)表示\(i\)这个位置变成1的最小代价。代价指什么呢?代价就是在之前不确定的位置上需要放几个1,也就是放几个大于等于\(mid\)的数,这个位置\(i\)才能变成1。那么对于原序列中的1,\(f[i] = 0\),原序列中的0,\(f[i] = inf\)。我们想让最后取出的中位数大于等于\(mid\),就得求出\(f[t]\)\(t\)是中位数的位置,如果\(f[t] <= res\),那么这个\(mid\)就符合条件。

​ 然后我们按题意模拟,把队列里前三个取出。只有当这前三个数有两个1的数时,当前这三个的中位数才为1,所以我们要取其中两个最小的\(f\)值,把它放到后面就好了。至于一定会有两个0的情况,那说明这个中位数一定为0,相同的操作把它加到后面就好了,不会有影响。

#include <bits/stdc++.h>

using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}
    
const int N = 2e5 + 5;
const long long inf = 2e8;
int n, m, t, ans;
int a[N], b[N], f[N];

int judge(int mid) {
    int res = 0;
    for(int i = m + 1;i <= n; i++) res += (b[i] >= mid);
    for(int i = 1;i <= n; i++) 
        f[i] = a[i] ? (a[i] >= mid ? 0 : inf) : 1;  
    queue <int> q;   
    for(int i = 1;i <= n; i++) q.push(f[i]);
    while(!q.empty()) {
        int x = q.front(); q.pop();
        if(q.empty()) return x <= res;
        int y = q.front(); q.pop();
        int z = q.front(); q.pop();
        q.push(min(min(x + y, x + z), y + z));
    }
}

signed main() {

    int l = inf, r = 0;
    n = read(); m = read();
    for(int i = 1, x, y;i <= m; i++) b[i] = read(), x = read(), a[x] = b[i], l = min(l, b[i]), r = max(r, b[i]);
    for(int i = m + 1;i <= n; i++) b[i] = read(), l = min(l, b[i]), r = max(r, b[i]);
    
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(judge(mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%d", ans);

    fclose(stdin); fclose(stdout);
    return 0;
}   

总结

​ 预计得分:100 + 100 + 50 = 250pts; 实际得分: 100 + 90 + 40 = 230pts。

​ 第三题爆零了,暴力不会打,这也太菜了。还是做题少吧,毕竟当时一点思路也没有。

​ 第二题我只想到两个,记忆化也没想到,还是多做题吧,以后应该就能想到了。

posted @ 2020-10-03 21:12  C锥  阅读(113)  评论(0编辑  收藏  举报