浙江十套 - 第一套 - 解题报告

  1. 漂亮字符串
    如果maxO == 0 说明只有x, 答案就是maxX
    如果X不够用,说明每次都是放maxO个O,用一个X隔开 OOOOOXOOOOOX.....
    此时有countO >= (countX + 1) * maxO
    因此,最大是countX + (countX + 1) * maxO;

注意更新

#include <iostream>
#include <cstdio>
long long CountO, CountX, maxO, maxX;

int main() {

    freopen("bs.in","r",stdin);
    freopen("bs.out","w",stdout);

    while (scanf("%lld%lld%lld%lld", &CountO, &CountX, &maxO, &maxX)) {
        maxX = std::min(maxX, CountX);
        maxO = std::min(maxO, CountO);
        if (maxO == 0)
            printf("%lld\n", maxX);
        else if (maxX == 0)
            printf("%lld\n", maxO);
        else if (CountO > (CountX + 1) * maxO)
            printf("%lld\n",CountX + (CountX + 1) * maxO);
        else if (CountX > (CountO + 1) * maxX) 
            printf("%lld\n", CountO + (CountO + 1) * maxX);
        else
            printf("%lld\n", CountX + CountO);
    }
    return 0;
}

2.Set
一个线性筛 + 并查集 (有倍数关系)

#include <cstdio>
#include <iostream>
using namespace std;

const int maxn = 100001;
bool pflag[maxn];
int prime[maxn>>1];
int fa[maxn];
int A, B;
int prime_cnt = 0;
int ans;
int P;

inline void Prime_Filter() {
    for (int i = 2; i <= B; ++ i){
        if(!pflag[i]) prime[ ++ prime_cnt] = i;
        for (int j = 1; j <= prime_cnt && prime[j] * i <= B; ++ j){
            pflag[prime[j] * i] = true;
            if ( i % prime[j] == 0) break;
        }
    }
}

inline int getRoot(int x) {
    if (x == fa[x]) return x;
    return fa[x] = getRoot(fa[x]);
}

bool judgeEqual(int x,int y) {
    return getRoot(x)==getRoot(y);
}

inline void join(int x,int y) {
    x = getRoot(x), y = getRoot(y);
    fa[y] = x;
}

inline void init() {
    cin >> A >> B >> P;
    ans = 0;
    for (int i = 1; i <= B; ++ i) {
        fa[i] = i;
    }
    Prime_Filter();
}

inline void solve() {
    int begin = 1;
    for (; prime[begin] < P; ++ begin);
    for (int k = prime[begin]; k <= B && k > 1; k = prime[++ begin]){
        for (int i = A/k*k, start = i; i <= B; start = i, i += k) {
            if (i < A || start < A) continue;
            if(!judgeEqual(i,start)) {
                join(i,start);
            }
        }
    }
    for (int i =A; i <= B; ++ i)
        if (fa[i] == i) ans ++;
}

int main() {
    freopen("set.in","r",stdin);
    freopen("set.out","w",stdout);
    init();
    solve();
    cout << ans;
}

3.Prison
动态规划经典题目,考的时候没有想出来优化,A得很水。。。。
用DP[i][j]表示在[i,j]区间所有该被释放的人都被释放的最小支付代价。
若是释放k,那么代价为DP[i][k-1]+DP[k+1][j]+(j-i)
这里的sum[i]指的是前i个位置中有多少犯人无法被释放。

#include <iostream>
#include <cstdio>
#include <algorithm>
const int MAX = 1010;
const int Inf = 0x7fffffff;
int n, m, a[MAX], sum[MAX], DP[MAX][MAX];

inline void init() {
    for (int i = 0; i < MAX; ++ i) {
        std::fill(DP[i], DP[i] + MAX, Inf);
        DP[i][i] = 0;
    }
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++ i)
        scanf("%d", &a[i]);
    std::sort(a + 1, a + m + 1);
    
    for (int i = 1; i <= m; ++ i)
        sum[i] = a[i] - a[i - 1] - 1;
    sum[m + 1] = n - a[m];
    for (int i = 1; i <= m + 1; ++ i)
        sum[i] = sum[i] + sum[i-1];
}

inline void solve() {
    for (int i = m + 1; i >= 1; -- i)
        for (int j = i + 1; j <= m + 1; ++ j)
            for (int k = i; k < j; ++ k)
                DP[i][j] = std::min(DP[i][j], DP[i][k] + DP[k + 1][j] + sum[j] - sum[i - 1] + j - i - 1);
}

int main() {
    freopen("prison.in","r",stdin);
    freopen("prison.out","w",stdout);
    init();
    solve();
    printf("%d\n", DP[1][m+1]);
    return 0;
}

4.Tree
这个还在打,待会传。

猜你喜欢

转载自www.cnblogs.com/Alessandro/p/9154628.html