实习笔试题目

携程2022.04.14

一个数组,一些数是'R',一些是'B', 取两个不同颜色的数,且数值相等,多少种取法
输入
5
1 2 1 2 2
BRRBB
输出
3

把蓝色数每个数值的个数用map存起来,遍历红色,把对应的数值个数取出来累加即可,int会炸

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int main(){
	string s;
	ll n, ans = 0;
	map<int, int> mp;
	cin >> n;
	int a[n + 1];
	for(int i = 0; i < n; i++)
		cin >> a[i];
	cin >> s;
	for(int i = 0; i < n; i++)
		if(s[i] == 'B') mp[a[i]] ++;
	for(int i = 0; i < n; i++)
		if(s[i] == 'R') ans += mp[a[i]];
	cout << ans << endl;
	return 0;
}

题目大意:一个数字串。从中选取一个子序列使其实9的倍数,有多少种方案,允许有前导0,对1000000007取模
输入
1188
输出
5
输入
0123
输出
1

位数值之和是9的倍数则序列是9的倍数,遍历数串,当前值可取可不取,若取则会对前面的值产生影响,若当前数值为x,则依次加0~9之后会对应更新,不取的话就是本身,则新的值就是dp[i][j + x] = dp[i - 1][j] + dp[i - 1][j + x],用滚动数组维护就行。

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int main(){
	string s;
	cin >> s;
	ll vis[2][10], flag = 0; // 维护9个数字的个数
	memset(vis, 0, sizeof(vis));
	for(int i = 0, x; i < s.size(); i++){
		x = s[i] - '0';
		x %= 9;
		for(int j = 0; j < 9; j++){
			int k = (j + x) % 9;
			vis[flag][k] = (vis[flag ^ 1][j] + vis[flag ^ 1][k]) % mod; // 当前数字取 or 不取
		}
		vis[flag][x] = (vis[flag][x] + 1) % mod; //单独作为一个序列
		// for(int j = 0; j < 9; j++)
		// 	cout << vis[flag][j] << " ";
		// cout << endl;
		flag ^= 1; // 更新状态,用两个数组交替维护
	}
	cout << vis[flag ^ 1][0] << endl; // 最后所有数字取完之后,0对应的数字就是方案的数目
	return 0;
}

给定一个01字符串, 如10101010110,每次可以交换相邻的字符使得01交替出现。确保字符合法。
11100
3
这里给一个用归并排序实现的

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int a[200005], b[200005], ans = 0;
void MergeArrays(int *a, int left, int mid, int right, int *b)
{
    int l = left,r = mid + 1,t = left;
    while(l <= mid && r <= right){
    	if(a[l] < a[r]){
    		ans += max(0, l - t);
    		b[t] = a[l];
    		l++; t++;
    	}else{
    		ans += max(0, r - t);
    		b[t] = a[r];
    		r++; t++;
    	}
    }
    while(l <= mid){
    	ans += max(0, l - t);
    	b[t++]=a[l++];
    } 
    while(r <= right){
    	ans += max(0, r - t);
    	b[t++] = a[r++];
    }
    t = left;
    while(left<=right) a[left++]=b[t++];
}
void MergeSort(int *a, int left, int right, int *b)
{
    if(left >= right) return ;
    int mid = left + right>>1;
    MergeSort(a, left, mid, b);
    MergeSort(a, mid+1, right, b);
    MergeArrays(a, left, mid, right, b);
}
void dfs(string s, char ch){
	int n = s.size(), l = 0, r = 1;
	for(int i = 0; i < n; i++){
		if(s[i] == ch){
			a[i] = l;
			l += 2;
		}else{
			a[i] = r;
			r += 2;
		}
	}
	MergeSort(a, 0, n - 1, b);
}
int main(){
	string s;
	cin >> s;
	int o1 = 0, o0 = 0, inf;
	for(int i = 0; i < s.size(); i++)
		s[i] == '1' ? o1 ++ : o0 ++;
	if(o1 > o0){
		dfs(s,'1');
		inf = ans;
	}
	else if(o1 < o0){
		dfs(s,'0');
		inf = ans;
	} 
	else {
		dfs(s, '1');
		inf = ans;
		ans = 0;
		dfs(s, '0');
		inf = min(inf, ans);
	}
	cout << inf <<endl;
	return 0;
}

网易互娱

缓存命中,有一个LRU(最近最少使用)缓存的访问记录R,记录量为m,大小为n,计算缓存的命中次数
输入
[1, 2, 1, 3, 2], 2
输出
1
解释
初始缓存为[]
访问1,未命中,更新为[1]
访问2,未命中,更新为[2, 1]
访问1,命中,更新为[1, 2]
访问3,未命中,更新为[3, 1]
访问2,未命中,更新为[2, 3]

思路,对每次询问,做个累加记录,和上一次相同的不变,不同的继续累加,更新映射,查询时差值小于n-1在缓存中命中,不在则未命中

int main(){
	map<int, int> a, b;
	int x, n, m;
	vector<int> v;
	cin >> m;
	for(int i = 0; i < m; i++){
		cin >> x;
		v.push_back(x);
	}
	cin >> n;
	n--;
	int ans = 0, cnt = 0;
	for(int i = 0; i < v.size(); i++){
		x = v[i];
		if(a[x] == 0) a[x] = ++cnt;
		else{
			if((cnt - a[x]) <= n) ans++;
			if(a[x] == cnt) continue;
			else a[x] = ++cnt;
		}
	}
	cout << ans << endl;
	return 0;
}

一个n个结点m条边的无向图,每个结点权值已知[1, 109109], 定义一条边为权重为两个结点乘积末尾0的数量,删除一条边,可以获得这条边的价值, 保证图联通的情况下,最多可以获得多少价值
输入
n,mn,m [1, 105105]
a1,a2,…ana1,a2,…an
u,vu,v
⋯⋯
5 3
5 8 25
1 2
2 3
1 3
输出
2
求最小生成树,总权重减去最小生成树权重就是价值

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int a[100005][2], f[100005];
void solve(long long int x, int y){
	int ans = 0;
	while(x % 5 == 0){
		a[y][0] ++;
		x /= 5;
	}
	while(x % 2 == 0){
		a[y][1] ++;
		x /= 2;
	}
}
int find(int x){
	return f[x] = f[x] == x ? x : find(f[x]);
}
int main()
{
	int n, m, inf = 0, ans = 0;
	cin >> n >> m;
	ll c;
	memset(a, 0, sizeof(a));
	for(int i = 1; i <= n; i++){
		cin >> c;
		solve(c, i);
	}
	vector<vector<int>> edge(m, vector<int>());
	for(int i = 0, l, r,y; i < m; i++){
		cin >> l >> r;
		edge[i].push_back(l); edge[i].push_back(r);
		y = min(a[l][0] + a[r][0], a[l][1] + a[r][1]);
		edge[i].push_back(y);
		inf += y;
	}
	sort(edge.begin(), edge.end(), [](vector<int>& o1, vector<int>& o2){
		return o1[2] <= o2[2];
	});
	for(int i = 0; i <= n; i++)
		f[i] = i;
	for(int i = 0, x, y; i < m; i++){
		x = find(edge[i][0]);
		y = find(edge[i][1]);
		if(x == y) continue;
		ans += edge[i][2];
		f[x] = y; n--;
		if(n == 1) break;
	}
	cout << inf - ans << endl;
	return 0;
}

定义一个区间的权值为区间内所有树的乘积末尾0的数量,求∑ni=1∑nj=1f(i,j)∑i=1n∑j=1nf(i,j)
输入
nn [1, 105105]
a1,a2,…ana1,a2,…an [1, 109109]
3
10 2 5
输出
5
一个数若有x个末尾0,那么分解这个数以后必定至少有x个5,x个2
统计每个数2,5的数量
计算前缀和a[n], a[i]为[1-i]2的数量或者5的数量,因此,1被累加了n次,i被累加了n-i+1次
并把全部前缀和加到树桩数组
查询时,从左到右依次查询,每次查询过后就要将当前位置本身对应的2,5的数量从树桩数组中剪掉其剪掉的值为-1 * (n - i + 1) * x。

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int a[100005][4], dp[2][100005];
void solve(int x, int y){
    int ans = 0;
    while(x % 5 == 0){
        a[y][0] ++;
        x /= 5;
    }
    while(x % 2 == 0){
        a[y][1] ++; x /= 2;
    }
}
int lowbit(int x){
    return (x & (-x));
}
void add(int x, int k, int val){
    for(int i = x; i < 100005; i += lowbit(i))
        dp[k][i] += val;
}
int query(int x, int k){
    int ans = 0;
    for(int i = x; i; i -= lowbit(i))
        ans += dp[k][i];
    return ans;
}
int main(){
    int n, inf = 0;
    cin >> n;
    memset(a, 0, sizeof(a));
    memset(dp, 0, sizeof(dp));
    for(int i = 1, x; i <= n; i++){
        cin >> x;
        solve(x, i);
    }
    for(int i = 1; i <= n; i++){
        a[i][2] = a[i][0];
        a[i][3] = a[i][1];
        a[i][0] += a[i - 1][0]; // 区间1-i的2, 5的总个数
        a[i][1] += a[i - 1][1];
    }
    for(int i = 1; i <= n; i++){
        add(i, 0, a[i][0]);
        add(i, 1, a[i][1]);
    }
    for(int i = 1; i <= n; i++){
        inf += min(query(n, 0), query(n, 1));
        add(i, 0, -(a[i][2] * (n - i + 1))); // 剪掉所有包含当前i的区间
        add(i, 1, -(a[i][3] * (n - i + 1)));
    }
    cout << inf << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tp_0moyi0

新手入行,慢慢学习,慢慢积累

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值