网易笔试 0923

记错了开考时间导致三点10分才开始答题。时间不够了,就AC了前三道,第四题全输出1骗了14.29%。

第一题给定一个长度为n的数组下标从0到n-1,然后第 i 和第(i+2)%n可以交换,问任意次交换后,能否使得数组不严格单调递增。

方法是先判n是否是奇数,是奇数那所有位置之间都可以交换,为Yes,为偶数就是分奇数位和偶数位排序然后比较是否后一位大于前一位。

#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
const int N = 1e5 + 20;

int n;
int a[N], b[N];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 0; i < n; ++i)
			cin >> ((i + 1) % 2 ? a[i / 2] : b[i / 2]);
		if (n % 2)
		{
			puts("YES");
			continue;
		}
		sort(a, a + n / 2);
		sort(b, b + n / 2);
		int flag = 1;
		for (int i = 0; i < n / 2 - 1; ++i)
			if (a[i] > b[i] || a[i + 1] < b[i])
			{
				flag = 0;
				break;
			}
		if (a[n / 2 - 1] > b[n / 2 - 1])
			flag = 0;
		puts(flag ? "YES" : "NO");
	}
	return 0;
}

第二题给n个字符串,问有多少组字符串是类似的。“类似的”的定义是各个字母出现个数相同。比如aabbd和abadb

方法是哈希,然后在处理第i个字符串时,统计之前有多少字符串是与其类似的。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 19260817;
const ll INF = 1e18 + 7;

int n;
ll ans;
string s;
map<ll, int> mp;
int a[30];

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n;
	while (n--)
	{
		cin >> s;
		for (auto p : s)
			++a[p - 'a'];

		ll tot = 0;
		for (int i = 0; i <= 25; ++i)
			tot = (tot * MOD + a[i]) % INF;
		if (mp.count(tot))
			ans += mp[tot], ++mp[tot];
		else
			mp.insert({tot, 1});

		for (auto p : s)
			--a[p - 'a'];
	}
	cout << ans << endl;
}

第三题问给定数组的所有子序列平均数之和。

方式是算每个数字对结果的贡献,比如[1,2,3,4]。1贡献为1的有一个,[1]。1贡献为1/2的有三个,[1,2],[1,3],[1,4]。1贡献为1/3的有3个,贡献为1/4的有1个。就是C^{i}_{n-1} / i+1,其中 i 从1遍历到n-1。然后 p / q 要转变成 p * q ^ {MOD - 2} 。

#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll INF = 1e9 + 7;
const int N = 1e5 + 20;

int n;
int a[N];

ll qpow(ll x, ll y)
{
    ll res = 1;
    while(y)
    {
        if(y&1) res=res*x%INF;
        x=x*x%INF;
        y>>=1;
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    ll tot = 0;
    for(int i=1;i<=n;++i)
    {
        cin >> a[i];
        tot += a[i];
    }
    tot %= INF;
    ll val = 1, sum = 1, up = n - 1, down = 1;
    for(int i=2;i<=n;++i)
    {
        sum = sum * up % INF;
        sum = sum * qpow(down, INF - 2) % INF;
        up--;
        down++;
        // cout << sum << ' ' << sum * 1.0 / i << endl;
        val = (val + sum * qpow(i, INF - 2) % INF) % INF;
    }
    cout << val * tot % INF << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

第四题是给定一棵n个节点的树,q次询问。每次询问一个点集,问多少个简单路径可以覆盖该点集。

受HDU5758启发。每次询问的时候构建一个虚树,答案为(虚树叶子数目+1)/2。如果根只有一个儿子时,也视为一个叶子。因为叶子不可能被不为它为端点的简单路径覆盖,所以叶子必定要是简单路径端点之一。

#网易#
全部评论
给大佬跪了,50分钟做了我两个小时的事情
1 回复 分享
发布于 2023-09-23 16:32 四川
第四题我有个思路,就是定义“伪叶子节点”为该节点为被标记的节点,且它的子树中不存在被标记的节点。那么答案为 “伪叶子节点”个数/2 (向上取整)
1 回复 分享
发布于 2023-09-23 17:29 广东
大佬牛逼!
点赞 回复 分享
发布于 2023-09-23 16:31 上海
第一题一模一样的思路,用vector内存超限,我麻了
点赞 回复 分享
发布于 2023-09-23 17:35 浙江
强啊
点赞 回复 分享
发布于 2023-09-23 17:46 湖北
ios::sync_with_stdio(true);?
点赞 回复 分享
发布于 2023-09-23 18:17 天津
T4判断查询点集中哪些是虚树叶子节点: 可以用树的dfs序将点重新编号,然后维护一颗线段树,每次查询将点集中线段树上对应位置标记为1,查询线段树区间和可以得到子树存在多少带标记的点。 判断虚树根节点是否为叶子: 取点集中最浅的点,查询其是否存在某一子树,其中标记点数恰好等于点集大小-1 目前想到的优化是线段树可以换别的数据结构,不知道有没有更优的解法
点赞 回复 分享
发布于 2023-09-24 01:58 广东
第二问,设计哈希函数很巧妙,当时这题一直超时卡50%
点赞 回复 分享
发布于 2023-09-26 12:10 上海
为什么p / q 要转变成 p * q ^ {MOD - 2}
点赞 回复 分享
发布于 2023-10-04 12:50 北京

相关推荐

11-13 20:32
门头沟学院 Java
面向未来编程code:我没看到他咋急,他不就问你个问题。。。
点赞 评论 收藏
分享
6 17 评论
分享
牛客网
牛客企业服务