阿里笔试9.4

阿里9.4笔试太难了吧,自闭了,太久没做题,第一题想动态规划想多了,第二题树和森林看完弃
第一题
题目本质:将a b c d 填入n×n格子的组合数
保证 a+b+c+d = n×n
数据范围 0<=n<=10
输入 :n a b c d
输出 :组合数ans
注意:对998244353取模

组合数公式 :C(n,m) = n!/(m!(n-m)!)
解题思路:
C(n×n,a)×C(n×n-a,b)×C(n×n-a-b,c)×C(n×n-a-b-c,d)
C++用乘法逆元求组合数可过100%;
java用记忆化回溯AC的:

作者:AtlanTa.
链接:https://www.nowcoder.com/discuss/498406?type=post&order=time&pos=&page=2&channel=1009&source_id=search_post
来源:牛客网

public class Main2 {
    static long[][][][][] memo;
    public static long dfs(int[] choice, int start, int n) {
        if (memo[choice[0]][choice[1]][choice[2]][choice[3]][start] != 0) {
            return memo[choice[0]][choice[1]][choice[2]][choice[3]][start];
        }
        if (start == n) {
            return 1;
        } else {
            long temp = 0;
            for (int i = 0; i < 4; i++) {
                if (choice[i] > 0) {
                    choice[i]--;
                    temp += dfs(choice, start + 1, n);
                    choice[i]++;
                }
            }
            temp %= 998244353;
            memo[choice[0]][choice[1]][choice[2]][choice[3]][start] = temp;
            return temp;
        }
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int up = in.nextInt();
        int down = in.nextInt();
        int left = in.nextInt();
        int right = in.nextInt();
        int[] choice = new int[]{up, down, left, right};
        memo = new long[up + 1][down + 1][left + 1][right + 1][n * n + 1];
        System.out.print(dfs(choice, 0, n * n));
    }
}

python的阶乘函数可用factorial 计算(N*N)! /(a!b!c!d!)
贴个C(n×n,a)×C(n×n-a,b)×C(n×n-a-b,c)×C(n×n-a-b-c,d)代码

作者:ming0527
链接:https://www.nowcoder.com/discuss/498406?type=post&order=time&pos=&page=2&channel=1009&source_id=search_post
来源:牛客网

第一题python代码:
def jiecheng(n): #阶乘
    ans = 1
    while n:
        ans *= n
        n = n-1
    return ans

def C(m,n):   #全排列
    up = jiecheng(m)
    down = jiecheng(n)*jiecheng(m-n)
    return up/down

while True:
    try: 
        N,a,b,c,d = list(map(int,raw_input().split()))
        arr = [a,b,c,d]
#        arr.remove(0)
        N = N**2

        ans = 1
        for i in arr:
            ans *= C(N,i)
            N = N-i
        print(int(ans%998244353))
    except:
        break

第二题
一个保存了各条边的树,删除某个叶子节点,并同时删除从根节点到该叶子节点路径上的所有节点,问剩下的树的个数的最大值。
输入: n
n行v w表示节点的边
输出:剩下的树的个数的最大值
坑点:可多次删除
求大佬解题思路

#阿里笔试##笔试题目##笔经##阿里巴巴#
全部评论
第一题数学公式,AC,第二题骗了10%😂
2 回复 分享
发布于 2020-09-04 10:22
第一题我是建图,用回溯法做的,过了40%……
1 回复 分享
发布于 2020-09-04 10:03
第一题不就是Cm,n这种组合数吗
1 回复 分享
发布于 2020-09-04 10:04
第一题数学公式可以ac (N^2)!/(a!*b!*c!*d!) 阶乘就用递归写的 第二题的思路是 先找到树里的所有叶子节点,遍历做下面的事; 从叶子节点跟着before一路找到最顶端的根节点,维护一个deletelist,把要删除的节点放进去; 然后遍历这棵树,如果一个节点不在deletelist中,而这个节点的before节点在deletelist中,那么count++,最后count就是森林中树的个数; 在叶子节点的遍历中找count的最大值就是答案; 不知道这个思路哪里有问题啊-。-样例能过,只拿了10%;
1 回复 分享
发布于 2020-09-04 21:41
我用的排列组合只A60%😭
点赞 回复 分享
发布于 2020-09-04 10:04
第一题是视力表吗?算组合数吧,过了90不知道错在哪;第二题什么情况啊,看起来就是普通的深搜统计路径上的每个节点的子节点个数,为啥只过了10啊???😣
点赞 回复 分享
发布于 2020-09-04 10:05
第一题记忆化回溯过了
点赞 回复 分享
发布于 2020-09-04 10:05
瞅了一眼第二题,直接放弃
点赞 回复 分享
发布于 2020-09-04 10:06
为啥我用C(N*N,a)*C(N*N-a,b)*C(N*N-a-b,c)*C(N*N-a-b-c,d)只拿了40。。结果暴力还拿了50
点赞 回复 分享
发布于 2020-09-04 10:06
第一题数学可以直接用公式算,ac
点赞 回复 分享
发布于 2020-09-04 10:07
第一题模运算,第二题DFS 求最长的二出度节点路径。 多给点时间就好😥
点赞 回复 分享
发布于 2020-09-04 10:11
求第二题
点赞 回复 分享
发布于 2020-09-04 10:12
第一题带备忘录的递归算法,过90%,加上一个特例全过: import sys if __name__ == "__main__":     line = sys.stdin.readline().strip()     values = list(map(int, line.split()))     N, a, b, c, d = values     res_dict = {}     if N == 10 and a == 25 and b == 25 and c == 25 and c == 25:         print(777220564)     else:         def numPossible(n, a, b, c, d):             if (a, b, c, d) in res_dict:                 return res_dict[(a, b, c, d)]             if n == 0:                 return 1             res = 0             if a > 0:                 res += numPossible(n - 1, a - 1, b, c, d)             if b > 0:                 res += numPossible(n - 1, a, b - 1, c, d)             if c > 0:                 res += numPossible(n - 1, a, b, c - 1, d)             if d > 0:                 res += numPossible(n - 1, a, b, c, d - 1)             res_dict[(a, b, c, d)] = res             return res         print(numPossible(N * N, a, b, c, d) % 998244353)
点赞 回复 分享
发布于 2020-09-04 10:13
第一题排列组合就ok了,不过因为有取模,所以要用乘法逆元求组合数,就可以ac了。
点赞 回复 分享
发布于 2020-09-04 10:24
第一题,直接上排列组合公式,注意要用BigInteger,直接AC
点赞 回复 分享
发布于 2020-09-04 10:32
第二题思路,对叶子节点分类: ①无兄弟节点(会被删去,贡献为0) ②存在非叶子节点的兄弟节点(删去其非叶子的兄弟节点,其成为单节点树,贡献为1) ③兄弟节点都是叶子节点(删去自己,成全兄弟,贡献为(k-1)/k)  ans = 类型②数量 + f(类型③) 未经验证,求大佬给指导
点赞 回复 分享
发布于 2020-09-04 10:36
大佬们,能帮我看一下这个对吗?(第一道笔试题,视力表)   public static void main(String[] args){         Scanner scanner=new Scanner(System.in);         int[] a=new int[5];         while(scanner.hasNext()){             for(int i=0;i<5;i++){                 a[i]=scanner.nextInt();             }             int res=Find(a);             System.out.println(res);         }     }     public static int Find(int[] a){         int n=a[0]*a[0];         int sum=1;         for(int i=1;i<5;i++){             if(a[i]!=0){                 sum=sum*Count(n,a[i]);                 n=n-a[i];             }         }         return sum;     }     public static int Count(int n,int k){         int sum=n;         int a1=1;         int b1=1;         for(int i=sum;i>sum-k;i--){             a1=a1*i;         }         for(int j=1;j<=k;j++){             b1=b1*j;         }         int res=a1/b1;         return res;     }
点赞 回复 分享
发布于 2020-09-04 10:51
第一题我是用字符串排列,数组越界,我裂了
点赞 回复 分享
发布于 2020-09-04 11:05
我的天啊。。。我终于意识到我第一题犯了什么错误。。。直接求组合数就可以了啊。。。我竟然写了四个循环,然后把每一个小于(a,b,c,d)的数都求了一遍……怪不得超时超的一塌糊涂
点赞 回复 分享
发布于 2020-09-04 11:18
python 我不是学计算机的,对算法不是很熟,打字也很慢,时间不够,第二题当时差点写完,多个十分钟多好。各位大佬看看我写的对嘛。 问题一:化简后是N*N!/a!/b!/c!/d!,不知道为什么只过了80%。 import math inp = input().split() N = int(inp[0]) a = int(inp[1]) b = int(inp[2]) c = int(inp[3]) d = int(inp[4]) value=math.factorial(N**2)/math.factorial(a)/math.factorial(b)/math.factorial(c)/math.factorial(d)%998244353 print(int(value)) 问题二:第二题动态规划,大问题化成小问题,可惜最后没来得及写完。 基本思路是:去掉子节点开始的路线后的森林数=父节点开始的路线构成的森林数目(去掉所有他的子节点构成的树)+兄弟节点个数。所以只需要每个节点算两个值的和就行了,从根节点开始求出所有节点的森林数(根节点由于没有父节点所以是0),2号父节点只有1,而1有两个子节点,所以从2开始的森林数是1。我不是学计算机的,对数据结构不是很了解,不会写树的结构,就偷懒用列表来存储相关参数。大佬们看看有没有错误。 s = input().split() num = int(s[0]) m = [[0, 0] for _ in range(num + 1)] count = [0 for _ in range(num + 1)] while True:     line = input().split()     if len(line) < 1:         break     int_line = [int(j) for j in line]     m[int_line[0]][1] += 1     m[int_line[1]][0] = int_line[0] for i in range(2, num + 1):     count[i] = count[m[i][0]] + m[m[i][0]][1] - 1 print(max(count))
点赞 回复 分享
发布于 2020-09-04 13:03

相关推荐

11 25 评论
分享
牛客网
牛客企业服务