2021浙大软院预推免记录

个人情况

    江浙沪地区某中流不知名211,无论文科研,有一个省级优秀的数据挖掘项目,和几个没有获过奖的服务外包之类的项目,参加过很多ACM竞赛。有一些学生工作的任职,校ACM队长和CTF队长,都和学术/竞赛挂钩。

    很早就有了保研的打算,也试着报名了一(hen)些(duo)夏令营。但是因为暑假还没有出综合排名,只能用成绩排名去投夏令营,导致几乎没有过初审的,甚至连本校的夏令营初审都被拒了,所以一直到九月中旬,我还是一个offer都没有,只能每天关注更新的预推免消息,不断地海投、海投……这是最焦虑的时期,一度认为自己没有学校上了。
    转机出现在9.20,日常打开报名过的每个学校预推免系统,意外地发现浙大软院的初审居然通过了,我决定抓住这次机会……

预推免复试

机试(2020.9.23 14:00-17:00)

    由于没有计划上浙大,过初审也很突然,我没有考过PAT,所以尽管看着大家在20年7月那次很水的PAT中全都是满分的成绩很眼馋,也无奈只能参加机试。机试我其实不是很担心,因为自己毕竟有一些ACM的经历,也参加过浙大承办的天梯赛,所以9.23号下午的机试过程及其放松。这里复盘一下当时的题目吧:
    总共有四道题,难度逐渐提升:

1.求多项式相乘系数

    对于一个多项式 ( x − a 1 ) ( x − a 2 ) ⋯ ( x − a n ) (x-a^{}_{1})(x-a^{}_{2})\cdots(x-a^{}_{n}) (xa1)(xa2)(xan),给定 a 1 a^{}_{1} a1 a n a^{}_{n} an的值(均为整数),求相乘后除最高次项以外各项的系数。
    这题还是比较水的,直接模拟乘的过程就好了。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 15;

int a[maxn],b[maxn],c[maxn];

int main(){
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
    b[0] = 1;
    for(int i = 1;i <= n;i++){
        memset(c,0,sizeof(c));
        for(int j = 0;j < maxn;j++){
            c[j] += b[j] * -a[i];
            c[j+1] += b[j];
        }
        memcpy(b,c,sizeof(c));
    }
    bool flag = false;
    for(int i = maxn-1;i >= 0;i--){
        if(b[i] && !flag){
            flag = true;
            continue;
        }
        if(flag)printf("%d%c",b[i],i==0?'\n':' ');
    }
    return 0;
}

2.最值问题

    给出三个集合 s 1 , s 2 , s 3 s^{}_{1},s^{}_{2},s^{}_{3} s1,s2,s3(每个集合至多1e4个元素),从每个集合中分别取出一个数,分别记为 a , b , c a,b,c a,b,c,求 ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ |a-b| + |b-c| + |c-a| ab+bc+ca的最小值和此时的 a , b , c a,b,c a,b,c如果有多种 a , b , c a,b,c a,b,c得到相同的最小值,输出三元组 ( a , b , c ) (a,b,c) (a,b,c)更大的一个
    首先明确不能采用 O ( n 3 ) O(n^{3}_{}) O(n3)的枚举,因为必然会超时。但这道题没能拿满分,因为算法fake了。我的想法是把三个集合融合成一个集合 s s s,然后遍历 s s s中的每一个元素 x x x,找到三个集合中最小的满足 ≥ x \geq x x的值作为 a , b , c a,b,c a,b,c。这个思路显然可以得到 ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ |a-b| + |b-c| + |c-a| ab+bc+ca的最小值,但是不能满足三元组 ( a , b , c ) (a,b,c) (a,b,c)是最大的。反例: ( 1 , 2 , 5 ) (1,2,5) (1,2,5) ( 1 , 4 , 5 ) (1,4,5) (1,4,5)的答案相等,而后者三元组更大。
    所以赛后整理了一下思路,首先,我们可以根据 a , b , c a,b,c a,b,c的相互大小关系对 ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ |a-b|+|b-c|+|c-a| ab+bc+ca分类讨论,可以发现该式的值等于 2 ∗ ( m a x − m i n ) 2*(max-min) 2(maxmin)。我们枚举 ( a , b , c ) (a,b,c) (a,b,c)中的最大元素 m a x max max,即遍历 s s s中的每一个元素 x x x,找到三个集合中最大的满足 ≤ x \leq x x的值作为 a , b , c a,b,c a,b,c,验证 ∣ a − b ∣ + ∣ b − c ∣ + ∣ c − a ∣ |a-b| + |b-c| + |c-a| ab+bc+ca的值是否更优即可。
    10.03更新,下面代码已经满分。
第二题

#include <bits/stdc++.h>
using namespace std;

int n[4];
set<int>s[4];

int calc(int a,int b,int c){
    return abs(a-b) + abs(b-c) + abs(c-a);
}

int main(){
    for(int i = 1;i <= 3;i++)scanf("%d",&n[i]);
    for(int i = 1;i <= 3;i++)
    for(int j = 1;j <= n[i];j++){
        int x;
        scanf("%d",&x);
        s[0].insert(x);
        s[i].insert(x);
    }
    int ans = 0x3f3f3f3f,a,b,c;
    for(auto & x : s[0]){
        auto it1 = s[1].upper_bound(x);
        auto it2 = s[2].upper_bound(x);
        auto it3 = s[3].upper_bound(x);
        if(it1 == s[1].begin() || it2 == s[2].begin() || it3 == s[3].begin())continue;
        it1--,it2--,it3--;
        if(ans >= calc(*it1,*it2,*it3))ans = calc(*it1,*it2,*it3),a = *it1,b = *it2,c = *it3;
    }
    printf("MinD(%d, %d, %d) = %d\n",a,b,c,calc(a,b,c));
    return 0;
}

3.并查集+结构体排序

    在一场比赛中,每个人有一个四位数的编号。给出一个人的部分队友列表(可能不完整)和这个人的分数,队友的队友也视为自己的队友,每个队的队长为该队内序号最小的一个。要求按照队伍总分为第一关键词、队伍人数为第二关键词、队长序号为第三关键词排序,输出每个队的队长序号、队伍总分、队伍人数。
    并查集能很好地处理这种关系传递情况,所以用并查集合并具有队友关系的每两个人,为了保存“队长”的信息,合并时应以序号较小的节点作为较大的节点的父亲。
    然后就是常规的结构体排序,直接重载小于运算符即可。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 10010;

int fa[maxn],score[maxn];
int find(int x){
    return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

int merge(int x,int y){
    int fx = find(x),fy = find(y);
    if(fx < fy)fa[fy] = fx;
    else fa[fx] = fy;
}

struct node{
    int id,score,s;
}p[maxn];

bool operator < (const node& a,const node& b){
    if(a.score == b.score && a.s == b.s)return a.id < b.id;
    if(a.score == b.score)return a.s < b.s;
    return a.score > b.score;
}
set<int>st;
int main(){
    int id,k,n;
    scanf("%d",&n);
    for(int i = 0;i < maxn;i++)fa[i] = i;
    for(int i = 1;i <= n;i++){
        scanf("%d %d",&id,&k);
        st.insert(id);
        int x;
        while(k--){
            scanf("%d",&x);
            st.insert(x);
            merge(id,x);
        }
        scanf("%d",&score[id]);
    }
    for(auto & x : st){
//        printf("%04d ",x);
        int y = find(x);
        if(y == x)p[x].id = x;
        p[y].score += score[x];
        p[y].s++;
    }
//    puts("");
    vector<node>v;
    for(auto & x : st)
    if(p[x].s)v.push_back(p[x]);
    sort(v.begin(),v.end());
    printf("%d\n",v.size());
    for(auto & x : v)
    printf("%04d %d %d\n",x.id,x.s,x.score);
    return 0;
}

4.堆排序

    超市搞促销,有 n n n种商品和 n n n种优惠,每种商品有无限个,同种商品只能用每种优惠一次。现在有 m m m块钱,问最多能买多少件商品,在保证买到件数最多的情况下,最多还能剩多少钱?数据保证每种商品优惠后至少还有1块钱,不会存在白给和倒贴的现象。
    理解起来可能有些抽象,来看一组样例:

三样商品价格分别为7,9,13
三种优惠分别为2,5,6
初始有12元钱
则对于第一种商品,可以通过1,2,5,7,7,7……的价格买到,对于第二种商品,可以通过3,4,7,9,9,9……的价格买到,对于第三种商品,可以通过7,8,11,13,13……的价格买到
可以买第一种商品最便宜的两件,第二种商品最便宜的两件,买到4件,余2元。

    做法:使用一个优先队列,对于每种商品放进去一个三元组(哪种商品,价格,用了第几个优惠),每次从优先队列取出来一个当前最便宜的商品,加进去一个该类商品次贵的三元组。循环该过程即可。需要注意的是,出题人假设所有商品都要用优惠买,当没有了优惠之后不按原价购买。

#include <bits/stdc++.h>
using namespace std;
static const int maxn = 100010;
int a[maxn],b[maxn];

struct node{
    int x,y,z;
};

bool operator <(const node& i,const node& j){
    return i.y > j.y;
}

int main(){
    int n,m;
    scanf("%d %d",&n,&m) ;
    for(int i = 1;i <= n;i++)scanf("%d",&a[i]);
    for(int i = 1;i <= n;i++)scanf("%d",&b[i]);
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    reverse(b+1,b+1+n);
    priority_queue<node>pq;
    for(int i = 1;i <= n;i++)pq.push(node{i,a[i] - b[1],1});
    int ans = 0;
    while(!pq.empty()){
        node p = pq.top();
        pq.pop();
        if(m < p.y)break;
        ans++;
        m -= p.y;
        if(p.z < n)pq.push(node{p.x,a[p.x] - b[p.z+1],p.z+1});
    }
    printf("%d %d\n",ans,m);
    return 0;
}

在这里插入图片描述

面试(9.28-9.29)

    浙软的面试需要提前至少两天提交个人陈述材料,没提交的就当作弃考了,所以做ppt还是很重要的,内容要不多不少,恰好讲够八分钟,自己要多锻炼,找hxd模拟面试几次。正式面试的时候老师们围坐在一个圆桌上,对着一个大屏幕,麦克风离老师有点儿远,我说了好多遍“老师您可以大点儿声吗?我听不太清楚”,然后老师重复几遍之后我才发现问的问题我不会- -这就很尴尬。。不过好在有惊无险,发挥中规中矩,多亏老师看得见机试分数,还是得了一个不错的分数。

后记

    浙软出结果非常快,全部面试完第二天上午就出结果了,详细地记录着每个人机试和面试的分数,非常透明。就打算上岸浙软了,菜鸡能去华五已经很满意辽~

  • 11
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值