Codeforces Round 986 (Div. 2)题解记录(A~E)
不知道cf重新交通过会重新算积分,直接多扣了300积分,真难绷,引以为戒吧
比赛链接:https://codeforces.com/contest/2028
A. Alice's Adventures in "Chess"
爱丽丝正试图在乡村与红皇后会面!目前,爱丽丝位于位置
更正式地说,如果爱丽丝在点
- 向北移动(用N表示),移动到
; - 向东移动(用E表示),移动到
; - 向南移动(用S表示),移动到
;或者 - 向西移动(用W表示),移动到
。
爱丽丝的移动是预先确定的。她有一个字符串 ,代表她从左到右执行的一系列移动。一旦她到达序列的末尾,她将永远重复相同的移动模式。
你能帮爱丽丝计算出她是否最终会与红皇后相遇吗?
每个测试包含多个测试用例。第一行包含测试用例的数量
每个测试用例的第一行包含三个整数
第二行包含一个长度为
对于每个测试用例,输出一个字符串“YES”或“NO”(不带引号),表示爱丽丝最终是否会与红皇后相遇。
6
2 2 2
NE
3 2 2
NNE
6 2 1
NNEESW
6 10 10
NNEESW
3 4 2
NEE
4 5 5
NEWS
YES
NO
YES
YES
YES
NO
思路:她将永远重复相同的移动模式。这句话很重要,爱丽丝在一次循环中不一定会遇到红皇后,显然最坏每次循环后最坏移动0或1,因为数据范围很小直接重复循环1000次(多次)就好,看看是否遇到就好,这里脑抽,赛后一个多小时又交了一发
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n,a,b;
cin>>n>>a>>b;
string f;
cin>>f;
ll cnt,ans;
cnt=ans=0;
ll pd=0;
ll i=0;
ll gs=4000;
while(1)
{
if(cnt==a&&ans==b)
{
pd=1;
break;
}
gs--;
if(gs==0)
break;
if(f[i]=='N')
{
ans++;
}
else if(f[i]=='S')
{
ans--;
}
else if(f[i]=='E')
{
cnt++;
}
else if(f[i]=='W')
cnt--;
i++;
if(i==n)
{
i=0;
}
}
if(pd)
cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
B. Alice's Adventures in Permuting
爱丽丝把“变换”和“排列”这两个词搞混了!她有一个由三个整数
现在,爱丽丝非常喜欢
你能帮爱丽丝计算出她需要进行多少次操作才能使
每个测试包含多个测试用例。第一行包含测试用例的数量
每个测试用例只有一行,包含三个整数
对于每个测试用例,如果数组永远无法变成一个排列,输出
7
10 1 0
1 2 3
100 2 1
3 0 1
3 0 0
1000000000000000000 0 0
1000000000000000000 1000000000000000000 1000000000000000000
0
1
50
2
-1
-1
1000000000000000000
思路:给的序列其实是个以c为初项,以b为公差的等差数列,
1.首先思考下不可能条件吧:如果对于目前最右边的最大数,每次变换后仍然是他最大就是不可能情况,对于一个公差不为0的等差数列,显然是不会出现这种情况的
所以思考公差为0的情况,枚举下初项为1,4可发现,如果c+1<n-1一定无解
2.有解次数,如何最小化?
其实只要看在这个序列中多个已经符合n排列的数的种类就行了,
如n=4,b=2,c=0时排列一开始为0 2 4 6,显然,对于每个不符合的数每次会变成符合的数,而且符合的数他是不用变的(当只有一个时)
所以当b>0时,直接根据公式b*i+c<=n-1,求出i(c>n-1时,这里会得出i<0),否则i=0,然后如果c<=n-1,则i++,否则i不变,最后和n取个min就得出答案了
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n,b,c;
cin>>n>>b>>c;
if(b==0&&c+1<n-1)
{
cout<<-1<<endl;
continue;
}
else
{
ll gs=0;
ll x=n-1;
if(b>0)
gs=(x-c)/b;
if(c<=n-1)
gs++;
cout<<min(n-gs,(ll)n)<<endl;
}
}
}
C. Alice's Adventures in Cutting Cake
爱丽丝在疯帽子的茶会上!有一个由
爱丽丝将把蛋糕切成
爱丽丝希望确保每个生物都满意。在这一条件下,她还希望最大化她自己那块蛋糕的美味度。你能帮爱丽丝找到她那块蛋糕的最大美味度吗?如果没有办法确保每个生物都满意,请输出
每个测试包含多个测试用例。第一行包含测试用例的数量
每个测试用例的第一行包含三个整数
下一行包含
所有测试用例中
对于每个测试用例,输出爱丽丝能够获得的最大美味度,或者如果没有办法确保每个生物都满意,则输出
7
6 2 1
1 1 10 1 1 10
6 2 2
1 1 10 1 1 10
6 2 3
1 1 10 1 1 10
6 2 10
1 1 10 1 1 10
6 2 11
1 1 10 1 1 10
6 2 12
1 1 10 1 1 10
6 2 12
1 1 1 1 10 10
22
12
2
2
2
0
-1
思路:我们一开始肯定无法直接知道从什么点开始到什么点结束为爱丽丝能拿的最大美味度,所以既然我不知道,那我每个都试试呗
首先用前缀和后缀数组wz1,wz2处理好到某个点能有多少个人被分配好蛋糕,还要用另一个前缀数组pre处理好前缀和,随后将后缀数组转成正序数组,然后每到i就知道已经分好了wz1[i-1]个人,所以还要分m-wz1[i-1]个人,直接二分(lower_bound)那个正序数组找到第一个符合的下标i1,然后n-i1,(记得二分包含0位置哦),即可得到爱丽丝在符合题意状况下能拿到的区间蛋糕(pre[n-i1]-pre[i-1]),在所有可能中取个最大值就好
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll pre[250000];
ll sub[250000];
ll wz1[250000];
ll wz2[250000];
ll a[250000];
ll ok[250000];
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n,m,v;
cin>>n>>m>>v;
for(ll i=1;i<=n;i++)cin>>a[i],sub[i]=0,pre[i]=0,wz1[i]=0,wz2[i]=0;
sub[n+1]=0;
ll sum=0;
for(ll i=1;i<=n;i++)
{
sum+=a[i];
pre[i]=pre[i-1]+a[i];
wz1[i]=max(wz1[i],wz1[i-1]);
if(sum>=v)
{
sum=0;
wz1[i]++;
}
}
sum=0;
wz2[n+1]=0;
for(ll i=n;i>=1;i--)
{
sum+=a[i];
wz2[i]=max(wz2[i],wz2[i+1]);
if(sum>=v)
{
wz2[i]++;
sum=0;
}
ok[n-i+1]=wz2[i];
}
// cout<<wz1[n]<<endl;
if(wz1[n]<=m-1)
{
cout<<-1<<endl;
}
else
{
ll ans=0;
for(ll i=1;i<=n;i++)
{
ll x=wz1[i-1];
ll u=m-x;
ll op=lower_bound(ok,ok+1+n,u)-ok;
ans=max(ans,pre[n-op]-pre[i-1]);
}
cout<<ans<<endl;
}
}
}
D. Alice's Adventures in Cards
爱丽丝正在和红心皇后、红心国王以及红心杰克玩牌。在他们的牌游戏中有
在这个牌游戏中,爱丽丝可以和另外三个玩家交换牌。每个玩家对
如果对于玩家的排列
确定爱丽丝是否可以根据这些偏好,从类型为
每个测试包含多个测试用例。第一行包含测试用例的数量
每个测试用例的第一行包含一个整数
接下来的三行包含皇后、国王和杰克的偏好。这些行每行包含
所有测试用例中
对于每个测试用例,在第一行输出一个字符串"YES"或"NO"(不包括引号),表示爱丽丝是否可以交易到牌
如果第一行是"YES",那么在下一行输出
你可以以任何情况(大写或小写)输出这个答案。例如,字符串"yEs"、"yes"、"Yes"和"YES"将被视为肯定的回应。同样,表示交易中玩家的字符
2
3
1 3 2
2 1 3
1 2 3
4
2 3 1 4
1 2 3 4
1 4 2 3
YES
2
k 2
q 3
NO
错误版思路:这个大家不要看,直接去看下面正确版的,这里留着是为了警示自己以后要留心点,其实记忆化递归卡过去是侥幸的,当然现在这个被hack了。由答案可知,我得输出过程,所以一定是dfs或者bfs,思考下bfs,不好写,因为过程会有问题(数据储存量会太大),所以就dfs了,一开始想建边,但是明显 的时间复杂度,所以否决,然后想了下题目给了两个约束,即优先度,和爱丽丝只能换更大的数,显然如果我dfs,一个数搜过了,之后一定不会搜了,所以准备记忆化+dfs,然后在想的时候优化了下遍历时间,一开始用3个set根据权值(优先度)对于q,k,j的手牌进行排序,随后开了两个二维数组,一个记录对应数的位置,还有一个记录排序后的数随后直接dfs+记忆化(这里用的是两个二维数组)就过了,但是时间是1468ms,有点危险,看了下样例全是NO才是1468ms,其他都是<900ms就过了,所以如果要优化下,看下能否特判不行情况吧,这里也脑抽重新交了一发,积分--,具体时间复杂度自己也不清楚
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
set<pair<ll,ll>>q[4];
bool vis[250000];
vector<pair<char,ll>>ans;
ll pd=0;
ll n;
ll a[4][250000];
ll b[4][250000];
void dfs(ll x)
{
vis[x]=1;
if(x==n)
{
pd=1;
return ;
}
ll wz;
wz=a[1][x];
// ll op=0;
for(ll i=wz+1;i<=n;i++)
{
if(b[1][i]>x&&vis[b[1][i]]==0)
{
ans.push_back({'q',b[1][i]});
dfs(b[1][i]);
if(pd)
return ;
ans.pop_back();
}
}
wz=a[2][x];
for(ll i=wz+1;i<=n;i++)
{
if(b[2][i]>x&&vis[b[2][i]]==0)
{
ans.push_back({'k',b[2][i]});
dfs(b[2][i]);
if(pd)
return ;
ans.pop_back();
}
}
wz=a[3][x];
for(ll i=wz+1;i<=n;i++)
{
if(b[3][i]>x&&vis[b[3][i]]==0)
{
ans.push_back({'j',b[3][i]});
dfs(b[3][i]);
if(pd)return ;
ans.pop_back();
}
}
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
pd=0;
cin>>n;
ans.clear();
q[1].clear();
q[2].clear();
q[3].clear();
for(ll i=1;i<=3;i++)
{
for(ll j=1;j<=n;j++)
{
ll w;
cin>>w;
vis[w]=0;
q[i].insert({n-w+1,j});
}
ll cnt=0;
for(auto j:q[i])
{
cnt++;
a[i][j.second]=cnt;
b[i][cnt]=j.second;
}
}
dfs(1);
if(pd==0)
{
cout<<"NO"<<endl;
}
else
{
cout<<"YES"<<endl;
cout<<ans.size()<<endl;
for(auto j:ans)
{
cout<<j.first<<" "<<j.second<<endl;
}
}
}
}
正确思路:第一个版本被hack了,以为加个位置记忆可以过,忽略了他有变大约束,这样dfs始终都是没办法的,最终一定可以被hack的,因为总能构造出吃满时间的样例。其实这里用bfs时间复杂度更好直接 ,但是注意Alice约束怎么优化?直接每次以最小的点走一遍即可!这样子位置就可以记忆化了(因为走过了后续再走到被标记过的点一定是有任何没用的,如果记忆了,就直接break,时间复杂度为 .但是如何找答案路线?确实bfs不适合找路线(不然内存会爆),所以就dfs呗,在bfs的过程中,我直接在目前点和下个可行点建边,然后这样子最多n-1跳边,然后记忆化走一遍不就n的时间复杂度了,在走的过程中边存储答案就可以了,所以最后时间复杂度 ,dfs+bfs巧妙结合,即可,时间复杂度687ms,这里如果用加速流+int就会624ms,但是如果加速流+long long就会1609ms,有点奇怪。
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
// void fio()
// {
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
// }
inline ll read()
{
ll 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;
}
set<pair<ll,ll>>q[4];
bool vis[250000];
vector<pair<char,ll>>ans;
vector<pair<char,ll>>g[250000];
ll pd=0;
ll n;
ll a[4][250000];
ll b[4][250000];
bool vi[4][250000];
void bfs(ll x)
{
priority_queue<ll,vector<ll>,greater<ll>>q;
q.push(x);
vis[x]=1;
while(!q.empty())
{
ll x=q.top();
q.pop();
for(ll i=a[1][x];i<=n;i++)
{
if(vi[1][i])
break;
if(vis[b[1][i]]==0&&b[1][i]>x)
{
g[x].push_back({'q',b[1][i]});
if(b[1][i]==n)
{
pd=1;
break;
}
vis[b[1][i]]=1;
q.push(b[1][i]);
}
vi[1][i]=1;
}
for(ll i=a[2][x];i<=n;i++)
{
if(vi[2][i])
break;
if(vis[b[2][i]]==0&&b[2][i]>x)
{
g[x].push_back({'k',b[2][i]});
if(b[2][i]==n)
{
pd=1;
break;
}
vis[b[2][i]]=1;
q.push(b[2][i]);
}
vi[2][i]=1;
}
for(ll i=a[3][x];i<=n;i++)
{
if(vi[3][i])
break;
if(vis[b[3][i]]==0&&b[3][i]>x)
{
g[x].push_back({'j',b[3][i]});
if(b[3][i]==n)
{
pd=1;
break;
}
vis[b[3][i]]=1;
q.push(b[3][i]);
}
vi[3][i]=1;
}
}
}
void dfs(ll x)
{
vis[x]=1;
if(x==n)
{
pd=1;
return ;
}
for(auto j:g[x])
{
if(vis[j.second]==0)
{
ans.push_back(j);
dfs(j.second);
if(pd)
return ;
ans.pop_back();
}
}
}
int main()
{
// fio();
ll t;
t=read();
while(t--)
{
pd=0;
n=read();
ans.clear();
q[1].clear();
q[2].clear();
q[3].clear();
for(ll i=1;i<=3;i++)
{
for(ll j=1;j<=n;j++)
{
ll w;
g[j].clear();
w=read();
vis[w]=0;
vi[1][j]=vi[2][j]=vi[3][j]=0;
q[i].insert({n-w+1,j});
}
ll cnt=0;
for(auto j:q[i])
{
cnt++;
a[i][j.second]=cnt;
b[i][cnt]=j.second;
// cout<<j.second<<" ";
}
//cout<<endl;
}
bfs(1);
if(pd==0)
{
cout<<"NO"<<endl;
}
else
{
pd=0;
for(ll i=1;i<=n;i++)vis[i]=0;
//cout<<g[1][0].second<<endl;
dfs(1);
cout<<"YES"<<endl;
cout<<ans.size()<<endl;
for(auto j:ans)
{
cout<<j.first<<" "<<j.second<<endl;
}
}
}
}
E. Alice's Adventures in the Rabbit Hole
Alice 在兔子洞的底部!兔子洞可以被建模为一棵树
每一分钟,都会抛一枚公平的硬币。如果硬币正面朝上,Alice 可以移动到她当前位置的相邻顶点;否则,红心皇后会将 Alice 拉到皇后选择的相邻顶点。如果 Alice 最终出现在树的任何非根叶子上
假设他们俩都以最优策略行动,计算 Alice 从每个起始顶点
正式地说,设
每个测试包含多个测试案例。第一行包含测试案例的数量
每个测试案例的第一行包含一个整数
接下来的
保证所有测试案例中
对于每个测试案例,输出一行包含
2
5
1 2
1 3
2 4
3 5
9
1 2
2 3
4 5
5 6
7 8
8 9
2 4
5 7
1 499122177 499122177 0 0
1 499122177 0 332748118 166374059 0 443664157 720954255 0
样例解析:
Alice 从根(顶点
Alice 会立即在顶点
从其他两个顶点开始,Alice 逃脱的概率是
思路:一开始的思路错了,上水课时画了下图,发现红皇后最好策略应该是往离她最近的子树的叶子上走,爱丽丝就是往1走最好,然后推出了个错误式子,设dis[x]为x到以x为根的子树的叶子的最短距离,父亲节点的成功率为p,于是错误式子得出 ,这样总样例过了,然后wa2,随后还以为是直接找到最近叶子就好了,然后bfs了一遍,还是错在一样的点,遂看了下题解。其实思路从dis[x]出发是对的,但是究竟公式是什么?答案是 ,所以我只好认为x到离他最近的叶子节点路上在许多可能性中,只有 可能会到达叶子节点,好了,原理写完了,说下怎么实现,首先dfs一遍回溯传递最近的叶子节点距离,然后再dfs一遍,这次是算答案,每次要传递当前点的可能到下个点(特判1),最后答案得出
#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll long long
#define lowbit(x) (x & -x)
#define endl "\n"// 交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
// inline ll read()
// {
// ll 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;
// }
vector<ll>g[250000];
ll dis[250000];
ll z[250000];
ll dfs(ll x,ll fa,ll sd)
{
ll u=9999999999;
for(auto j:g[x])
{
if(j!=fa)
{
u=min(u,dfs(j,x,sd+1));
dis[x]=min(dis[x],u-sd);
}
}
if(x!=1&&g[x].size()==1)
{
u=sd;
dis[x]=min(dis[x],(ll)0);
}
return u;
}
void df(ll x,ll fa,ll v,ll sd)
{
if(x==1)
{
z[x]=v=1;
}
else if(dis[x]==0)
{
z[x]=v=0;
}
else
{
ll u=ksm(dis[x]+1,mod-2);
z[x]=v=(v%mod*((dis[x]%mod*u%mod)%mod)%mod)%mod%mod;
}
for(auto j:g[x])
{
if(j!=fa)
{
df(j,x,v,sd+1);
}
}
}
int main()
{
fio();
ll t;
cin>>t;
while(t--)
{
ll n;
cin>>n;
for(ll i=1;i<=n;i++)g[i].clear(),dis[i]=9999999999;
for(ll i=1;i<n;i++)
{
ll l,r;
cin>>l>>r;
g[l].push_back(r);
g[r].push_back(l);
}
ll j=dfs(1,0,1);
df(1,0,1,1);
for(ll i=1;i<=n;i++)
cout<<z[i]<<" ";
cout<<endl;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下