2025年2月月记

2025.2.15

哇!明天就要报到了,收拾一下东西吧(翻出我的作业)(当我发现我的寒假作业还没来得急做,就已经知道我该睡去了)算了不收拾了,晚上再说。前六天去集训了,没睡好,今天必须奖励睡到十一点半好吧。关于我为什么二月日记是从15号开始的?之前要么在玩,要么在集训,你说为什么。。。

下午到了,该整理一下错题了,先看看这道题(题目链接):

金牌鼓手

题目描述

在本场演出中,你一共需要敲击 N 次,每次敲击都有一定的精彩度 vi,整场演出
的总精彩度为每次敲击精彩度的总和。
为了使演出更有感染力,你会选择 K 次敲击进行重击,但是这会导致该次敲击的
精彩度降低,变为 vi × pi% ,其中 0 ≤ pi ≤ 100 。

你需要合理安排在哪一次敲击进行重击,使得整场演出的总精彩度最大,输出该最
大值。
总精彩度最大时,可能会有不同选择重击的方式,对于某些数据,你还需要输出该
总方案数。

输入格式

从文件 drum.in 中读入数据。
第一行三个整数 N,K,B,分别表示敲击的总次数,重击的总次数,B 为 1 时,
你需要输出方案数,为 0 时则不需要。
第二行 N 个整数,表示第 i 次敲击的精彩度 vi。
第三行 N 个整数,表示如果在第 i 次敲击选择重击,精彩度改变的百分数 pi。

输出格式

输出到文件 drum.out 中。
第一行输出一个小数,保留 5 位,表示最大的总精彩度。
如果读入的 B 为 1,你需要在第二行输出一个整数,表示方案数。

输入输出样例

输入 #1

5 2 0 
4 6 8 10 2 
50 50 50 50 50

输出 #1

27.00000

输入 #2

5 2 1
4 6 8 10 2
50 50 50 50 50

输出 #2

27.00000
1

提示/说明

样例1解释

选择第 1 次、第 5 次进行重击,最终的总精彩度为 4×50%+6+8+10+2×50% = 27,
能够证明这是最大的总精彩度。

子任务

对于测试点 1,保证所有 pi = 0。
对于测试点 2,保证 K = 0。
对于测试点 3 − 5,保证 N ≤ \(10^3\)
对于测试点 6 − 10,保证 N ≤ 5 × \(10^5\)
对于 30% 的测试点,保证 B = 0。
对于 100% 的测试点,保证 0 ≤ pi ≤ 100,0 ≤ N, K ≤ 5×\(10^5\),0 ≤ vi ≤ \(10^3\) B ∈ {0, 1}。

对于《金牌鼓手》这道题的错误分析与纠正

这是题目,很简单吧,我一开始也觉得很简单的,只要有眼睛就知道这是个很普通正常的贪心,但为人正直的我不怎么会贪,根据题目得知如果你选择重击当前的节奏,那他的精彩度只会降低,所以天真的我就按照原来的精彩度大小进行贪心,就优秀的拿到了20分。。。

那我们来想想正确的贪心策略:如果你选择重击,精彩度就会减少,那我们不如按照减少的多少来进行贪心,先用一个数组来存储如果第i次选择重击,那么会减少多少精彩度。然后对这个数组进行排序得出最终的答案。

那如果B为1呢?也很简单,只要认真分析,就能得出,如果我们想用不同的方案得出相同的答案,那么他们减少后的精彩度和他们原来的精彩度得是一样的。那我们只需要找到“可替代品”就能够让答案一样。

那我们再来看看具体该怎么求呢?如果已知有n个替代品,而我们需要m个,这不就是简简单单的排列组合了吗?我们只需要找排好序后的前k个差有多少个差和第k个差一样的和后k个有多少个差和第k个差一样的,对他进行排列组合即可。

《金牌鼓手》Code

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
struct stu{
    long long v;
    double p;
}a[N];
int n, k, op;
long long f[N];
map <double, int> box;
double sum;
bool cmp(stu x, stu y){
    return x.p < y.p;
}
long long calc(int n, int m){
    f[0] = 1;
    for(int i = 1; i <= 19; i++)
        f[i] = i * f[i - 1];
    return (f[n] / f[m]) / f[n - m];
}

int main(){
    freopen("drum.in", "r", stdin);
    freopen("drum.out", "w", stdout);
    cin >> n >> k >> op;
    for(int i = 1; i <= n; i++)
        cin >> a[i].v, sum += a[i].v;
    for(int i = 1; i <= n; i++){
        cin >> a[i].p;
        a[i].p = a[i].v - 1.0 * a[i].p * a[i].v / 100;
    }
    sort(a + 1, a + n + 1, cmp);
    for(int i = 1; i <= k; i++)
        sum -= a[i].p;
    printf("%.5lf\n", sum);
    if(op){
        int l = 0;
        for(int i = k; i >= 1; i--)
            if(a[i].p == a[k].p){
                box[a[i].p] ++;
                l ++;
            }   
            else break;
        for(int i = k + 1; i <= n; i++)
            if(a[i].p == a[k].p)
                box[a[k].p] ++;
            else break;
        cout << calc(box[a[k].p], l) << "\n";
    }
    return 0;
}

这道题整理完后我就去打上海月赛了,唉,不知道第四题错在哪,样例明明能过(当然,这证明不了什么)。不管了,今天就再看一道题吧(题目链接):

传输协议

题目描述

这个网络中一共有 N 个节点,有 M 条线路,每条线路传输信息需要一定的时间
wi。

现在有 Q 个用户,每个用户都有一个类型的请求 Ri 和自己所在的节点 Pi ,每个
类型的请求需要发送到对应类型的高性能服务器才能被解析。

为了节约成本,这 N 个节点中只有 K 个节点配置了高性能服务器,每台服务器都
有一个类型 Gi 和所在的节点 Fi。

每个用户的资源占用定义为用户发送请求到对应服务器所经过的最短时间。

为了提高该网络的传输效率,你需要对用户发送信息的行为进行限制(即忽略一些
用户的请求),使得在总资源占用不超过 T 的情况下,所有服务器解析用户请求的总数
量最多。

作为这个网络系统的管理员,你需要计算出所有服务器解析用户请求的总数量最多
是多少。

输入格式

从文件 protocol.in 中读入数据。
第一行五个整数,分别为 N,M,Q,K,T,具体含义如上。
接下来 M 行,每行三个整数,表示节点 xi 与 yi 之间存在一条线路,其传输信息
所用的时间为 wi。
接下来 Q 行,每行两个整数,表示用户 i 所处的节点 Pi 和请求类型 Ri。
接下来 K 行,每行两个整数,表示服务器 i 所处的节点 Fi 和类型 Gi。

输出格式

输出到文件 protocol.out 中。
输出一个整数,表示所有服务器解析用户请求的最大总数。

输入输出样例

输入 #1

4 4 2 2 4
1 2 2
2 3 3
3 4 1
2 4 6
1 1
2 2
3 1
4 2

输出 #1

1

提示/说明

样例1解释

用户 1 的资源占用为 5,用户 2 的资源占用为 4,则服务器解析用户请求的总数量
最多是 1。

子任务

对于测试点 1 − 4,保证 N ≤ 8,M ≤ 12。
对于测试点 5 − 12,保证 N ≤ \(10^3\),M ≤ \(10^4\)
对于测试点 13 − 20,保证 N ≤ \(10^4\),M ≤ 5 × \(10^4\)
对于 20% 的测试点,保证 K = 1。
对于 100% 的测试点,保证 1 ≤ N, Q, Pi, Fi ≤ \(10^4\),0 ≤ M ≤ 5 × \(10^4\),1 ≤ K ≤ 20,1 ≤ Ri, Gi, wi, T ≤ \(10^9\)
保证每个用户至多对应一个服务器,保证用户的位置是唯一的,服务器的位置也是唯一的。

对于《传输协议》这道题的错误分析与纠正

这道题明显是一道图论题,我当时也想到了,然后看了一下这个数据范围,心想:拿捏了!不就是个但愿最短路加贪心吗?这数据范围,随便......超时+内存爆了。

我是这样的思路(基本是正确的,但就是一些细节问题):首先存图,然后用Dijkstra求出每个节点进行搜索,找到所对应要求的人,最后用贪心求出最多人数的。但为什么会出现超时与内存爆炸呢?

先看内存爆炸,我只是把所有的内存限制搬上了代码,但有个小细节,就是在做Dijkstra时,我们用的是优先队列(STL库版),这么大的数据范围,只要你不用贪心优化一下,谁知道队列炸不炸?其实不会炸那到底是为什么炸了呢?因为我一开始使用dp求最多能满足的人数,数组炸了。。。我是傻子

再看时间为啥会爆,Dijkstra那一块代码得用贪心优化是真的,其次那个dp。。。

OK,清楚了问题所在就好说了,我们只需要按照我的思路简单的改一下就好了,首先建图,之后枚举每台机子,进行Dijkstra,搜索完后枚举n个点,记录当前机子到这个点的最小花费,最后对这个花费从小到大排序,计算出最大人数(就是这么简单)。

《传输协议》Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
struct Node{
    int x, w;
};
struct pq{
    int x, f;
    bool operator<(const pq &x) const{
        return f > x.f;
    }
};
vector <Node> mp[N];
vector <int> sum;
int n, m, Q, k, T, use[N], shell[N], pos[N], f[N];
bool vis[N];
void Dijkstra(int st){
    for(int i = 0; i <= n; i++){
        vis[i] = 0;
        f[i] = 1e18;
    }
    priority_queue <pq> q;
    q.push({st, 0});
    f[st] = 0;
    while(!q.empty()){
        int x = q.top().x, step = q.top().f; q.pop();
        if(f[x] != step || vis[x])
            continue;
        vis[x] = 1;
        for(auto i : mp[x]){
            int y = i.x, w = i.w;
            if(f[y] > f[x] + w){
                f[y] = f[x] + w;
                q.push({y, f[y]});
            }
        }
    }
}

signed main(){
    cin >> n >> m >> Q >> k >> T;
    while(m --){
        int u, v, w;
        cin >> u >> v >> w;
        mp[u].push_back({v, w});
        mp[v].push_back({u, w});
    }
    while(Q --){
        int x, y; cin >> x >> y;
        use[x] = y;
    }
    for(int i = 1; i <= k; i++){
        int x, y; cin >> x >> y;
        pos[i] = x;
        shell[x] = y;
    }
    for(int i = 1; i <= k; i++){
        Dijkstra(pos[i]);
        for(int j = 1; j <= n; j++)
            if(use[j] == shell[pos[i]] && f[j] != 1e18)
                sum.push_back(f[j]);
    }
    int ans = 0, cnt = 0;
    sort(sum.begin(), sum.end());
    for(auto x : sum){
        if(cnt + x <= T){
            ans ++;
            cnt += x;
        }
        else
            break;
    }
    cout << ans << "\n";
    return 0;
}

又解决了一道题,累死了,希望他能成为我攀岩高山的垫脚石吧。期待我的上海月赛是一等,但第四题是真的Speechless了,现在已经晚上5点35了敢信吗?我好像想起了我那尘封已久的寒假作业,吃完晚饭再说吧。

2025.2.16

今天就要去学校报道了,我似乎忘记了昨天晚上说的作业没写,算了,反正今天也不检查作业,晚上再说吧。今天起来的挺早,9点就起了(好像也不早)。又做了两道绿题,两道dp。昨天晚上打了个atcoder,A了前四题,第五题亖了,不清楚为什么,只能等老师给我解答了。

2025.2.22

时间过得也太快了,作为一个住校生,一周也写不了日记啊,绝对不是我不想写,昨天放学回来就开始上课了,学的时数论,脑袋都要给我干冒烟了,是真的没想到计算机的数学是这么的丝滑,今天又上了编程课,是S组的知识:负环。我是觉得负环挺简单的,不就是单源最短路的模板加了个计数数组吗?希望以后也顺利吧!

今天又打了两场比赛,atcoder是必须的!还有一场是小明月赛,只打了div3,感觉没啥难度,最大的难点应该就是他是OI模式吧,希望别爆了,好久没AK过比赛了,atcoder又是可恶的第五题不会,第一眼:嗯~是个很好的图论题,刚好最近在学。第二眼:我服了,那数据就跟没有似的,知一求四,我求你&&#(¥&#。
学校同学挺好学的,又给他录了两个讲解视频,虽然题难(对于他来说),但都是思维题+一些些技巧,大家都这么走过来的,就顺便教了他一些有趣的特性。
我看什么时候整理一下atcoder的第五题吧,好久没整理了,但现在很晚了(毕竟才打完atcoder),就先睡了,

晚安!!

2025.2.23

啊,明天就是死亡星期一了,完全不想上课。。。到了学校就基本碰不到电脑了,而且学校真就是“无罪的监狱”啊!学个习都要随时注意不要猝亖,那作业多的,直接就是上演了笔芯消失术是吧?真就“盐都不盐了”。
我是知道了学校的尿性,就没有“擅长科目”这个说法,我语文不好,老师说:“你看你语文,都快垫底了,来多给你布置点作业。”,我数学好,老师说:“看你数学挺好的,这个数学小报就由你来画了!”。我:“##)@#()¥@#(¥#%%(¥#(#¥(#%(¥#!”。

来说点正事,今天呢,没干啥,但又干了啥完成了老师布置的作业(编程与学校),又打了一场比赛(小明月赛-div2),从第5题开始,我就不行了。atcoder上周的第五题与这周的第5题都没订正。。。唉,时间真少——。明天又得早起了,今天得睡早点,所以

加纳!!

2025.2.26

学校又考了一场数学考试,唉,包拿满分的啊,全年级就只有我一个满分,这都是我一点一点积累出来的!(一个声音)“同学同学,你这个方法确实能拿满分,但还是太吃操作了,有没有更简单的办法?”,啊,有的,兄弟,有的。(做你梦去吧!)。开始涉及博客了,还不太会用,一切都慢慢来吧

posted @ 2025-02-28 18:40  Ryan_L_F  阅读(55)  评论(0)    收藏  举报
//雪花飘落效果