算法訓練(二)
阿新 • • 發佈:2018-11-20
ear set 二進制位 最短 lcm 相同 else for math
1.zoj-4049
簡單的進程模擬,大部分情況下可以直接出答案,當進入死循環的時候,不難發現,循環中所得值會出現重復,因此可視重復為死循環的標誌,使用一個bool數組進行標記即可,代碼如下:
#include <iostream> #include<cstring> using namespace std; const int N = 10100; const int Mod = 256; bool dp[N][257]; struct node { char op[4]; int v, k; }p[N]; bool check(int pos, intnum) { if (dp[pos][num]) return false; else return true; } int main() { int t; scanf("%d", &t); while (t--) { memset(p, 0, sizeof(p)); memset(dp, false, sizeof(dp)); int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", p[i].op); if (strcmp(p[i].op, "add") == 0) scanf("%d", &p[i].v); else scanf("%d%d", &p[i].v, &p[i].k); } int num = 0, pos = 1; bool flag = true; while (pos <= n && flag) { flag = check(pos, num);if (!flag) continue; dp[pos][num] = true; if (strcmp(p[pos].op, "add") == 0) { num = (num + p[pos].v) % Mod; pos++; } else if (strcmp(p[pos].op, "beq") == 0) { if (num == p[pos].v) pos = p[pos].k; else pos++; } else if (strcmp(p[pos].op, "bne") == 0) { if (num != p[pos].v) pos = p[pos].k; else pos++; } else if (strcmp(p[pos].op, "blt") == 0) { if (num < p[pos].v) pos = p[pos].k; else pos++; } else { if (num > p[pos].v) pos = p[pos].k; else pos++; } } if (flag) puts("Yes"); else puts("No"); } return 0; }
2.zoj-4057
通過分析可得,最短的序列的二進制位一定是要相同的,這樣最高位異或後皆為0,一定會比序列中最小的值還要小,所以只要求出二進制位數相同的最多的序列即可,代碼如下:
#include<cstdio> #include<cmath> #include<iostream> #include<string> #include<cstring> #include<algorithm> using namespace std; int a[35]; void init() { for (int i = 1; i <= 30; i++) { a[i] = (int)(pow(2, i)); } } int main() { int t; init(); scanf_s("%d", &t); while (t--) { int n; scanf_s("%d", &n); int sum[35] = { 0 }; for (int i = 0; i<n; i++) { int x; scanf_s("%d", &x); for (int j = 1; j <= 30; j++) { if (x<a[j]) { sum[j]++; break; } } } int ans = -1; for (int i = 1; i <= 30; i++) { ans = max(ans, sum[i]); } printf("%d\n", ans); } return 0; }
3.zoj-4056
可先畫時間軸,不難發現,整個時間軸其實是由多次循環得到的,於是我們可以先求出兩個時間的最小公倍數確定循環,因為每次燈泡只維持(v+0.5)s,所以將一個循環中的兩個時間的倍數壓進數組排序去重,燈沒亮的時候要花一次去按燈,循環中的算出來後還要跑一次多出來的不在循環中的即可,代碼如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; #define int long long vector<long long>V; int gcd(int a, int b) { if (b == 0) return 1; else return gcd(b, a%b); } int main() { int T; scanf("%lld", &T); while (T--) { int a, b, c, d, v, t; scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &d, &v, &t); long long te = gcd(a, c); long long lcm = a * c / te; V.clear(); for (int i = 0; i <= lcm; i += a) V.push_back(i); for (int i = 0; i <= lcm; i += c) V.push_back(i); sort(V.begin(), V.end()); V.erase(unique(V.begin(), V.end()), V.end()); int tmp = 0; for (int i = 1; i < V.size(); i++) { if (V[i] - V[i - 1] > v) tmp++; } long long ans = (t / a) * b + (t / c) * d + b + d - 1; long long cur = t / lcm; ans = ans - cur * tmp; long long la = t % lcm; for (int i = 1; V[i] <= la; i++) { if (V[i] - V[i - 1] > v) ans--; }4 cout << ans << endl; } }
算法訓練(二)