1. 程式人生 > >算法訓練(二)

算法訓練(二)

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, int
num) { 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;
    }
}

算法訓練(二)