2019年怀化学院校赛总结

来自一个很少写题解的咸鱼

    • 1001:工资
    • 1002:1的个数
    • 1003:板上钉钉
    • 1004:因子数
    • 1005:能量补充
    • 1006:蛋糕
    • 1007:服务
    • 1008:最大地雷区
    • 1009:矩阵
    • 1010:无限迷宫
    • 1011:Sequential game

这是第二次也是最后一次去参加怀化学院的校赛,一样的行程一样的住宿,C&V学长的安排就是轻松。大佬说写题解会收获多多,只会写简单题的我就来划划水了。
先放传送门,密码:hhtc20190607

1001:工资

温暖的签到题:范围不大,模拟即可,直接上代码。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 20007;

int k, a[MAXN];
int main() {
    int num = 0, cnt = 1;
    for(int i = 1; i < MAXN;) {
        for(int j = cnt; j > 0 && i < MAXN; j--) {
            num += cnt;
            a[i++] = num;
        }
        cnt++;
    }
    while(scanf("%d", &k) != EOF)
        printf("%d\n", a[k]);
    return 0;
}

1002:1的个数

求解n的二进制有多少个1,bitset直接解决。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 20007;

int n;
int main() {
    while(scanf("%d", &n) != EOF) {
        bitset<1000> bi(n);
        printf("%d\n", bi.count());
    }
    return 0;
}

1003:板上钉钉

打表得到结论,输出Yes当且仅当n是2的次幂,至于证明就不放了(不会啊)。
场上用的for判2的次幂,场下经学长提点可以判n的2进制中1的个数,于是又用了bitset。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 20007;

int n;
int main() {
    while(scanf("%d", &n) != EOF) {
        bitset<1000> bi(n);
        if(bi.count() == 1) puts("Yes");
        else puts("No");
    }
    return 0;
}

1004:因子数

当L==R时,最小的因子就是L的最小因子(场上因这个点还wa了TAT)。
当L < R时,最小的因子是2,显然的结论。
下面的代码用的for循环求最小因子,显然可以优化,不过对于这题的范围来说已经足够了。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 20007;

int l, r;
int main() {
    while(scanf("%d%d", &l, &r) != EOF) {
        if(l != r) puts("2");
        else {
            for(LL i = 2;; i++) {
                if(i * i > l) {
                    printf("%d\n", l);
                    break;
                }
                if(l % i == 0) {
                    printf("%lld\n", i);
                    break;
                }
            }
        }
    }
    return 0;
}

1005:能量补充

经典贪心问题:汽车加油的原题
场上信心满满的写,然后wa到怀疑人生,场下找了一天的bug才发现i++的位置放错了,造的数据也都过了,一失足成千古恨。
附上暖心的测试数据:
4 10
10 1
5 1
5 2
5 3

3 15
10 2
9 1
8 3

2 10
5 10
5 1

3 10
1 1
1 1
9 2

4 10
1 1
1 2
9 2
1 3

4 10
1 1
1 2
9 3
1 4

3 2
1 5
1 4
1 3

3 14
5 2
5 10
5 1

30
41
55
11
14
15
12
25

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 100077;

int n, t;
LL d[MAXN], p[MAXN];
int main() {
    while(cin >> n >> t) {
        bool pr = true;
        for(int i = 0; i < n; i++)  {
            cin >> d[i] >> p[i];
            if(d[i] > t) pr = false;
        }
        if(!pr) cout << -1 << endl;
        else {
            d[n] = p[n] = INF;
            LL ans = 0;
            LL neng = 0;
            int now = 0;
            while(now < n) {
                int r = now + 1;
                int idex = now + 1;
                LL num = t - d[now];
                while(num > d[r]) {
                    num -= d[r];
                    r++;
                    if(p[r] < p[idex]) idex = r;
                }
                if(p[now] <= p[idex]) {
                    if(r == n) {
                        LL sum = -neng;
                        for(int i = now; i < n; i++) sum += d[i];
                        ans += sum * p[now];
                        break;
                    } else {
                        ans += (t - neng) * p[now];
                        neng = t;
                        for(int i = now; i < idex; i++) neng -= d[i];
                        now = idex;
                    }
                } else {
                    LL sum = -neng;
                    int i;
                    for(i = now; i < r && p[i] >= p[now]; i++) sum += d[i];
                    ans += sum * p[now];
                    neng = 0;
                    now = i;
                }
            }
            cout << ans << endl;
        }
    }
    return 0;
}

1006:蛋糕

简单搜索题,从蛋糕的位置起搜索能到的点,然后再计数即可,注意蛋糕可能不止一个(场上数据出锅再次wa到怀疑人生)。
注:下面的代码是dfs递归过的,实际上考虑极限情况递归层数可以到1e6,爆栈警告,过了只能说数据不够强。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 1007;

int n, m;
char s[MAXN][MAXN];
char t[7] = {"swad"};
int dx[4] = { -1, 1, 0, 0};
int dy[4] = {0, 0, 1, -1};
bool check(int id, int x, int y) {
    if(x < 0 || x >= n) return false;
    if(y < 0 || y >= m) return false;
    if(s[x][y] != t[id]) return false;
    return true;
}
void dfs(int x, int y) {
    for(int i = 0; i < 4; i++) {
        int nex = x + dx[i];
        int ney = y + dy[i];
        if(check(i, nex, ney)) {
            s[nex][ney] = '*';
            dfs(nex, ney);
        }
    }
}
int main() {
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 0; i < n; i++) scanf("%s", s[i]);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(s[i][j] == 'o') dfs(i, j);
        int cnt = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(s[i][j] == '*' || s[i][j] == 'o') cnt++;
        printf("%d\n", cnt);
    }
    return 0;
}

1007:服务

简单模拟题居然爆零了,哭晕
开数组记录每台服务器当前的右边界,对于每个任务枚举判断并更新右边界即可。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 107;

int n, q;
int R[MAXN];
int check(int t) {
    int ret = 0;
    for(int i = 1; i <= n; i++)
        if(R[i] < t) ret++;
    return ret;
}
int jisuan(int t, int k, int d) {
    int num = t + d - 1;
    int ret = 0;
    for(int i = 1; k > 0; i++)
        if(R[i] < t) R[i] = num, k--, ret += i;
    return ret;
}
int main() {
    while(scanf("%d%d", &n, &q) != EOF) {
        memset(R, 0, sizeof(R));
        while(q--) {
            int t, k, d;
            scanf("%d%d%d", &t, &k, &d);
            if(check(t) >= k) printf("%d\n", jisuan(t, k, d));
            else puts("-1");
        }
    }
    return 0;
}

1008:最大地雷区

又是一道搜索题,先搜索出包含目标地点的地雷区,再计算出因两地雷相邻而减少的边数
周长=地雷数*4-减少边数

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 37;

int n, m, x, y;
char s[MAXN][MAXN];
int dx[8] = { -1, 1, 0, 0, -1, -1, 1, 1};
int dy[8] = {0, 0, 1, -1, 1, -1, 1, -1};
void dfs(int x, int y) {
    if(x < 0 || x >= n) return;
    if(y < 0 || y >= m) return;
    if(s[x][y] != 'X') return;
    s[x][y] = '*';
    for(int i = 0; i < 8; i++)
        dfs(x + dx[i], y + dy[i]);
}
int quchong(int x, int y) {
    int ret = 0;
    for(int i = 0; i < 4; i++) {
        int nex = x + dx[i];
        int ney = y + dy[i];
        if(nex < 0 || nex >= n) continue;
        if(ney < 0 || ney >= m) continue;
        if(s[nex][ney] != '*') continue;
        ret++;
    }
    return ret;
}
int main() {
    while(scanf("%d%d%d%d", &n, &m, &x, &y) != EOF) {
        for(int i = 0; i < n; i++) scanf("%s", s[i]);
        dfs(x - 1, y - 1);
        int cnt = 0, qu = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                if(s[i][j] == '*') {
                    cnt++;
                    qu += quchong(i, j);
                }
        printf("%d\n", cnt * 4 - qu);
    }
    return 0;
}

1009:矩阵

还是搜索题:dfs枚举每种走的方案+剪枝(没剪枝T了TAT)

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 37;

int n, m, k;
bool ans[MAXN];
int a[MAXN][MAXN];
bool f[MAXN][MAXN][MAXN];
void dfs(int num, int x, int y) {
    if(x < 0 || x >= n) return;
    if(y < 0 || y >= m) return;
    num = num * a[x][y] % k;
    if(x == n - 1 && y == m - 1) ans[num] = true;
    if(f[x][y][num]) return;
    f[x][y][num] = true;
    dfs(num, x + 1, y);
    dfs(num, x, y + 1);
}
int main() {
    while(scanf("%d%d%d", &n, &m, &k) != EOF) {
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
                scanf("%d", &a[i][j]);
        memset(f, false, sizeof(f));
        memset(ans, false, sizeof(ans));
        dfs(1, 0, 0);
        int cnt = 0;
        for(int i = 0; i < k; i++)
            if(ans[i]) cnt++;
        printf("%d\n", cnt);
        for(int i = 0; i < k; i++)
            if(ans[i]) printf("%d ", i);
        putchar('\n');
    }
    return 0;
}

1010:无限迷宫

至臻*自闭
理论AC的做法,把迷宫向外拓展一圈,如果能从中间的’S’走到外面的任意一个’S’即可无限远,然而我wa了

1011:Sequential game

字符串处理的题
题意:每加进来一个字符,如果和已有的字符最后一位不一样,则先反转再加上新字符,否则直接加上新字符。
直接模拟是可以过的,然而我们仔细考虑一下,整个串是0还是1只跟最后一个字符有关,所以直接判断最后一个字符然后输出字符串长度计即可。

const int INF = 0x3f3f3f3f;     ///1 061 109 567
const int negative_infinite = 0xcfcfcfcf;   ///-808 464 433
const int mod = 1000000007;
const double eps = 1e-5;
const int MAXN = 20007;

string s;
int main() {
    while(cin >> s) {
        int len = s.length();
        if(s[len - 1] == '0') cout << len << " " << 0 << endl;
        else cout << 0 << " " << len << endl;
    }
    return 0;
}

怀化之行结束了,第一次体验到没人带榜的感觉,我就是带榜的人,结果把榜带歪了 ,一开始装环境装的我头晕眼花的,但问题不大,看到题后感觉比去年容易了不少,应该没有难题,有AK的理论可能,遇到了很多问题,在场上要寻求速度对于很多的细节反而没把握好,也不应该死磕一两道题,场下才发现有简单题没动。果然大佬说的没错,在场上想要超常发挥相当的难,一般来说反而会比平时练习差一筹。快退役选手 弱鸡要准备期末考试了~

对于18级:本来看完题目后觉得这次应该稳了,花了这么多时间在搜索上,这次血赚,然后结束一看榜。。。不知道怎么形容当时的无语。。。

你可能感兴趣的:(题解)