【题解】牛客模考 · 大厂定制出题模拟笔试

A式计数法

难度:1星

知识点:模拟,字符串

题意:对于每个给定数字,使用A式计数法输出。

按照题意模拟即可。注意倒序处理。每隔A个字符输出一个'_'字符即可。
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int t=in.nextInt();
        for(int i=0;i<t;i++){
            int a=in.nextInt();
            String s=in.next(),out="";
            int cnt=0;
            for(int j=s.length()-1;j>=0;j--){
                if(cnt>0&&cnt%a==0)out='_'+out;
                cnt++;
                out=s.charAt(j)+out;
            }
            System.out.println(out);
        }
    }
}


质数之手

难度2.5星

知识点:数论、枚举

题意:给定n,找到最小一个正整数是n的数位重排、且是素数。若不存在则输出0

思路: 考虑到n不超过1e6,所以只需要把所有素数筛出来,然后枚举即可。

需要考虑以下限制条件:

  1. 必须是素数(可以用筛法解决,O(1)判断)

  2. 必须是n的重排(可以利用桶统计每个数的次数,O(10)判断)
import java.util.*;

public class Main{
    
    static boolean jud(int a,int b){					//判断是否构成重排
        int[] A=new int[10],B=new int[10];
        while(a>0){
            A[a%10]++;
            a/=10;
        }
        while(b>0){
            B[b%10]++;
            b/=10;
        }
        for(int i=0;i<10;i++)if(A[i]!=B[i])return false;
        return true;
    }
    static boolean[] pr;
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n=in.nextInt();
        pr = new boolean[1000010];
        for(int i=1;i<=1e6;i++)pr[i]=true;
        pr[1]=false;
        for(int i=2;i<=1e6;i++){
            if(pr[i]){
                for(int j=i*2;j<=1e6;j+=i){
                    pr[j]=false;
                }
            }
            
        }
        ArrayList<Integer> out = new ArrayList<Integer>();
        for(int i=1;i<=1e6;i++){
            if(jud(n,i)&&pr[i])out.add(i);
        }
        System.out.println(out.size());
        if(out.size()>0){
            System.out.println(out.get(0));
        }
    }
}


合成二叉树

知识点:贪心、二叉树

难度:3.5星。

思路:

使用贪心策略,优先合并两个节点数最小的树一定是最优解。

因此按题意模拟,把所有树放入优先队列,每次优先选择两个节点数最小的树进行合并即可。合并后再加入优先队列。
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
map<TreeNode*,int>siz;
map<TreeNode*,int>id;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param T TreeNode类vector 
     * @return TreeNode类
     */
    int getSiz(TreeNode *T)
    {
        if(T==nullptr)
            return 0;
        return getSiz(T->left)+getSiz(T->right)+1;
    }
    TreeNode* mergeTree(vector<TreeNode*>& T) {
        // write code here
        auto cmp=[](TreeNode*& a, TreeNode*& b)
        {
            if(siz[a]==siz[b])
                return id[a]>id[b];
            else
                return siz[a]>siz[b];
        };
        priority_queue<TreeNode*,vector<TreeNode*>,decltype(cmp)>q(cmp);
        int n=T.size();
        for(int i=0;i<n;i++)
        {
            siz[T[i]]=getSiz(T[i]);
            id[T[i]]=i;
            q.push(T[i]);
        }
        while(q.size()!=1)
        {
            TreeNode *a=q.top();
            q.pop();
            TreeNode *b=q.top();
            q.pop();
            if(siz[a]!=siz[b])
            {
                TreeNode *c=new TreeNode(1);
                if(siz[a]>siz[b])
                    swap(a,b);
                c->left=a;
                c->right=b;
                siz[c]=siz[a]+siz[b]+1;
                id[c]=n++;
                q.push(c);
            }
            else
            {
                TreeNode *c=new TreeNode(1);
                c->left=a;
                c->right=b;
                siz[c]=siz[a]+siz[b]+1;
                id[c]=n++;
                q.push(c);
            }
    	}
        return q.top();
    }
};


插班生

难度:5星

思路:

对于每个节点,我们可以通过预处理的方式达成 O(1) 的查询。

预处理方式如下:我们先只考虑插班生右方的学生。

如果第一个位置是插班生,那么右边的依次是 -(n-1) -(n-2),...,-2,-1

当插班生右移时,插班生右边的依次是 -(n-2),...,-2,-1

我们可以发现,当一个点会减成负的时,如果再将插班生右移,我们会发现剩下的一定都是负的。

因此可以把每个点的“会减成负的”的区间求出来,利用差分、前缀和达成区间的合并。这样就能批量处理,达成O(1)查询了。

对于插班生左边的学生,处理方式同右边。

#include <iostream>
using namespace std;
const int maxn = 1e5 + 5;
#define ll long long
#define int long long
ll pre[maxn], suf[maxn], pre2[maxn], suf2[maxn], sum[maxn], a[maxn];
signed main(){
	int n;
	cin >> n;
	ll ans = 0;
	for(int i = 1; i <= n; i++){
		cin >> a[i];
		ans += a[i];
	}
	for(int i = 1; i <= n; i++){
		if(a[i] >= n - 1)	continue;
		ll l = i - (n - a[i] - 1), d = 0;
		if(l < 1){
			d = - l + 1;
			l = 1;
		}
		pre[l]++;
		pre[i]--;
		pre2[l] += d;
		pre2[i] -= d + (i - l);
	}
	for(int i = n; i >= 1; i--){
		if(a[i] >= n - 1)	continue;
		ll r = i + (n - a[i] - 1), d = 0;
		if(r > n){
			d = r - n;
			r = n;
		}
		suf[r]++;
		suf[i]--;
		suf2[r] += d;
		suf2[i] -= d + (r - i);
	}
	for(int i = 1; i <= n; i++){
		pre[i] = pre[i-1] + pre[i];
		pre2[i] += pre[i] + pre2[i-1];
	}
	for(int i = n; i >= 1; i--){
		suf[i] = suf[i+1] + suf[i];
		suf2[i] += suf[i] + suf2[i+1];
	}
//	for(int i = 1; i <= n; i++){
//		cout << suf2[i] << " ";
//	}
	for(int i = 1; i <= n; i++){
		cout << ans - a[i] - (i-1) * i / 2 - (n-i) * (n-i+1) / 2 + suf2[i] + pre2[i] - 2 * (n - i) * (i - 1) << " ";
	}
}

#笔经#
全部评论
感谢楼主分享!
点赞 回复 分享
发布于 2022-01-12 19:58

相关推荐

机械打工仔:我来告诉你原因,是因为sobb有在线简历,有些HR为了快会直接先看在线简历,初步感觉不合适就不会找你要详细的了
投了多少份简历才上岸
点赞 评论 收藏
分享
评论
点赞
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务