Problem A 计划日

题目链接:http://nyoj.top/problem/1363

题意:给你一个日期和当天是星期几,求n天后的日期并求出是星期几。
思路:直接从那一天跑个循环就行了,简单的模拟一下,这里有个技巧就是用%md来读入日期。

#include <bits/stdc++.h>
using namespace std;
int a[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
int leap(int year) {
    return year % 100 && !(year % 4) || !(year % 400);
}
int main() {
    int t, w, n, year, month, day;
    scanf("%d", &t);
    while (t--) {
        scanf("%4d%2d%2d%d%d", &year, &month, &day, &w, &n);
        for (int i = 1; i <= n; i++) {
            if (day >= a[leap(year)][month]) {
                if (month >= 12) {
                    year++;
                    month = 0;
                }
                month++;
                day = 0;
            }
            day++;
        }
        printf("%04d%02d%02d %d\n", year, month, day, (n + w - 1) % 7 + 1);
    }
    return 0;
}

Problem B 治安管理

题目链接:http://nyoj.top/problem/1364

题意:给你每个保安的开始和结束的巡逻时间,判断s~f这个时间段的人数是不是都不少于m。
思路:直接求出每个时间点的人数,判断一下就行了。

#include <bits/stdc++.h>
using namespace std;
int p[100005];
int main() {
    int t, n, m, s, f, a, b, max_, min_, temp;
    scanf("%d", &t);
    while (t--) {
        temp = 1;
        max_ = 0;
        min_ = 0x3f3f3f3f;
        memset(p, 0, sizeof(p));
        scanf("%d%d%d%d", &n, &m, &s, &f);
        for (int i = 0; i < n; i++) {
            scanf("%d", &a);
            p[a]++;
        }
        for (int i = 0; i < n; i++) {
            scanf("%d", &b);
            p[b]--;
        }
        for (int i = 1; i < f; i++)
            p[i] += p[i - 1];
        for (int i = s; i < f; i++) {
            if (p[i] < m)
                temp = 0;
            max_ = max(max_, p[i]);
            min_ = min(min_, p[i]);
        }
        if (temp)
            printf("YES %d\n", max_);
        else printf("NO %d\n", min_);
    }
    return 0;
}

Problem C 山区修路

题目链接:http://nyoj.top/problem/1365

题意:给你一道高低不平的路,现在需要修路,修路需要算上高度差的花费,但是填高也需要费用,问修路的最小花费是多少。
思路:数组dp[i][j]表示第i座山高度为j的状态下,前i座山总的最少花费,dp[i][j]只和dp[i-1][k]相关,计算出第n座山在所有高度下的最小花费,其中最小值即为结果。
状态转移方程为:
dp[i][j] = min(dp[i][j], dp[i - 1][k] + abs(j - k) * x + (j - a[i]) * (j - a[i]));
好像NYOJ的数据加大了,老是时间超限,因为循环次数太多了,所以寄存器运行register起到了作用,register可以加快速度。

#include <bits/stdc++.h>
#define re register
using namespace std;
const int inf = 0x3f3f3f3f;
int dp[100005][105], a[100005];
int main() {
    int t, n, x;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &x);
        for (re int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        for (re int i = a[0]; i <= 100; i++)
            dp[0][i] = (i - a[0]) * (i - a[0]);//第一段没有高度差的费用,只有填高费
        for (re int i = 1; i < n; i++) {//当前的每一段路高
            for (int j = a[i]; j <= 100; j++) {//当前路的高度
                dp[i][j] = inf;
                for (re int k = a[i - 1]; k <= 100; k++)//当前路的前一段路的高度
                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + abs(j - k) * x);//找出最优的路的花费
                dp[i][j] += (j - a[i]) * (j - a[i]);//算上填高费
            }
        }
        int min_ = inf;
        for (re int i = a[n - 1]; i <= 100; i++)
            min_ = min(min_, dp[n - 1][i]);
        printf("%d\n", min_);
    }
    return 0;
}

Problem D 求XF+闭包

题目链接:http://nyoj.top/problem/1366

题意:给你一个x串,和一些函数依赖,求x的闭包XF+。
思路:直接模拟,先把X串中的元素都标记一下,然后就枚举函数依赖,只要S中的元素都在X中,并且T中的元素没在X中就把T中的元素更新到X中,直到X没有更新为止。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 30;
int vis[MAXN];
char ustr[MAXN], xstr[MAXN], s[MAXN][MAXN], t[MAXN][MAXN];
int main() {
    int T, n, m, k, flsg, fltg, temp;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d", &n, &m, &k);
        scanf("%s%s", ustr, xstr);
        for (int i = 0; i < k; i++)
            scanf("%s%s", &s[i], &t[i]);
        memset(vis, 0, sizeof(vis));
        for (int i = 0; xstr[i]; i++)
            vis[xstr[i] - 'A']++;
        while (true) {
            temp = 0;
            for (int i = 0; i < k; i++) {
                flsg = fltg = 0;
                for (int j = 0; s[i][j]; j++)
                    if (!vis[s[i][j] - 'A'])
                        flsg = 1;
                for (int j = 0; t[i][j]; j++)
                    if (!vis[t[i][j] - 'A'])
                        fltg = 1;
                if (!flsg && fltg) {
                    for (int j = 0; t[i][j]; j++)
                        vis[t[i][j] - 'A']++;
                    temp = 1;
                }
            }
            if (!temp)
                break;
        }
        for (int i = 0; i < 26; i++) {
            if (vis[i])
                printf("%c", i + 'A');
        }
        printf("\n");
    }
    return 0;
}

Problem F Gene mutation

题目链接:http://nyoj.top/problem/1368

题意:给了两组数,然后问第一组数中有多少个子数组加任意数或减任意数再任意排序得到第二组数。
思路:直接暴力寻找枚举每一个m长的子串,判断就行了。

#include <bits/stdc++.h>
using namespace std;
int n, m;
int pre[20005], ans[15], cnt[15];
int Check(int l, int r) {
    for (int i = l; i <= r; i++)
        cnt[i - l] = pre[i];
    sort(cnt, cnt + m);
    int flag = cnt[0] - ans[0];
    for (int i = 0; i < m; i++) {
        if (ans[i] + flag != cnt[i])
            return 0;
    }
    return 1;
}
int main() {
    int t, num;
    scanf("%d", &t);
    while (t--) {
        num = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
            scanf("%d", &pre[i]);
        scanf("%d", &m);
        for (int i = 0; i < m; i++)
            scanf("%d", &ans[i]);
        sort(ans, ans + m);
        for (int i = 0; i <= n - m; i++)
            if (Check(i, i + m - 1))
                num++;
        printf("%d\n", num);
    }
    return 0;
}

Problem H Attack City and Capture Territory

题目链接:http://nyoj.top/problem/1370

题意:有n个东西,可以全部破坏或者只破坏一部分,最后破坏的人获胜。
思路:尼姆博弈。

#include <bits/stdc++.h>
using namespace std;
int main () {
    int t, n, a, ans;
    scanf("%d", &t);
    while (t--) {
        ans = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &a);
            ans ^= a;
        }
        if (ans)
            printf("Liu_B is sure to win.\n");
        else printf("Liu_B is not sure to win.\n");
    }    
    return 0;
}