2023大厂真题提交网址(含题解):
www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
B.打表找规律
这里比赛的时候蠢了。其实一眼发现是平方数.至于(2000,2000)这个数据不是平方数。是因为他取过模了。。这里没想通导致自己蠢了.
H.线段树,思维
一眼线段树…题目说明了询问区间长度 ≤ \leq ≤ 3.我们应该要充分利用这个性质。不难发现,我们可以将左右端点分别维护.然后用简单的容斥去计算:
完全包含区间 [ L , R ] [L,R] [L,R]的线段个数 = 总线段个数 - [右端点 < < < R的线段]个数 - [左端点 > > > L的线段]个数 + 完全在区间 ( L , R ) (L,R) (L,R)中的线段个数.
前三项计算完,完全在区间 ( L , R ) (L,R) (L,R)中的线段个数会被减两次。所以需要加一下。而区间长度 ≤ \leq ≤ 3 ,我们完全可以存数组下来求一求.
我比赛的时候多组输入少写一个 '~'导致超时然后XJB交了8发才发现。。。离谱了。重回小学了.
J.dfs, 计数
刚才花20分钟补了一下。难度对标小白月赛。。感觉榜被带偏了。
这张图的特性:每个点有且仅有1个入度。并且从根节点到每个点的路径唯一.
子问题:给你一个序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an, a i ∈ [ 1 , n ] a_i \in [1,n] ai∈[1,n]问你有多少个不同的有序二元组 ( x , y ) (x,y) (x,y).
O ( n 2 ) O(n^2) O(n2)的做法就不说了,考虑 O ( n ) O(n) O(n)的做法:
考虑新增一个元素 a i a_i ai。它对答案的贡献受限于前一个 a i a_i ai出现的位置。
例如: 4,1,2,3,4 和 1,2,4,3,4 和 1,2,3,4,4 。这几组4对答案的贡献是不一样的.
自然我们想到记录上一次 a i a_i ai出现时,前缀中不同的数的个数cnt1。假设当前的前缀中不同的数的个数为cnt2.那么当前 a i a_i ai对答案的贡献为: c n t 2 − c n t 1 cnt2-cnt1 cnt2−cnt1
放到图上也是一样,跑个dfs.记得dfs完某个节点撤销状态即可.
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
const int maxn = 1e5 + 5;
vector<int> E[maxn];
ll ans[maxn] , book[maxn] , off[maxn] , cnt = 0;
int a[maxn];
void dfs (int u , int fa)
{
ans[u] = ans[fa] + cnt - off[a[u]];
int o = off[a[u]];
off[a[u]] = cnt;
if (book[a[u]] == 0) cnt++;
book[a[u]]++;
for (auto v : E[u]){
if (v == fa) continue;
dfs (v , u);
}
if (book[a[u]] == 1) cnt--;
book[a[u]]--;
off[a[u]] = o;
return ;
}
int main()
{
ios::sync_with_stdio(false);
int n;
while(cin >> n){
cnt = 0;
for (int i = 0 ; i <= n ; i++){
book[i] = ans[i] = off[i] = 0;
E[i].clear();
}
for (int i = 2 ; i <= n ; i++){
int x; cin >> x;
E[x].pb(i);
}
for (int i = 1 ; i <= n ; i++)
cin >> a[i];
dfs (1 , 0);
for (int i = 2 ; i <= n ; i++){
cout << ans[i] << endl;
}
}
return 0;
}