阿里笔试(0314算法岗)
时长:90分钟
总共6道单选+6道多选+3道编程
第一题:
比较简单,数据范围是1000,那么直接二层for循环模拟即可
#阿里笔试##阿里巴巴##笔经##include<stdio.h> int main() { int a, b, c, d, m; scanf("%d %d %d %d %d", &a, &b, &c, &d, &m); int ans = 0, x, y; for (x = a; x <= b; x++) for (y = c; y <= d; y++) if (ans < (x * y) % m) ans = (x * y) % m; printf("%d\n", ans); return 0; }
交换字符
这个题目出的很好,很多边界条件,组合数学
当交换2个相同的字符时,不会产生不同的字符串,因此我们可以用"所有交换的方案数" - "s 维持不变方案数"来得到答案
还要注意特判存在2个字母相同的情况,可以得到原串
#include<bits/stdc++.h> using namespace std; #define ll long long int main() { string s; cin >> s; ll n = s.size(); map<char, ll> M; for (auto ch: s) M[ch]++; ll tot = n*(n-1)/2; for (auto [k,v]: M) tot -= v*(v-1)/2; //存在2个相同的字母 for (auto [k,v]: M) if (v >= 2) { tot++; break; } cout << tot << endl; }
第三题:切割
第三题很难很难,最后才做出来:
做 2 次 dp
第一次 dp,求每个数模 k 等于 x,最少需要切割多少次 ;O(400x400x18)x 400` 个数
第二次 dp,用第一次dp 的结果,求前 i 个数模 k 等于 x,最少需要切割多少次,复杂度 O(400*400*400)
#include<bits/stdc++.h> using namespace std; typedef long long ll; vector<int> gao(ll n, int k) { string s = to_string(n); vector<vector<int>> dp(s.size()+1, vector<int>(k, 0x3f3f3f3f)); dp[0][0] = 0; for (int i = 0; i < s.size(); i++) { int cur = 0; for (int j = i; j < s.size(); j++) { cur = (cur * 10 + s[j]-'0')%k; for (int x = 0; x < k; x++) { dp[j+1][(cur+x)%k] = min(dp[j+1][(cur+x)%k] , dp[i][x]+(i!=0)); } } } return dp.back(); } int main() { int n, k; cin >> n >> k; vector<ll> A(n); for (auto &x: A) cin >> x; vector<int> cur(k, 0x3f3f3f3f); cur[0] = 0; for (auto &t: A) { vector<int> nxt(k, 0x3f3f3f3f); vector<int> tmp = gao(t, k); for (int i = 0; i < k; i++) { for (int j = 0; j < k; j++) nxt[(i+j)%k] = min(nxt[(i+j)%k], cur[i]+tmp[j]); } cur = nxt; } cout << cur[0] << endl; }