计蒜客 2018 蓝桥杯省赛 B 组模拟赛(一)题解

传送门
A: 直接暴力跑答案
ans = 1;

B: 还是暴力算模拟一遍即可
ans = 571;

C: 这道题还是暴力算有多少个满足条件的即可, 就是模拟的时候有点恶心, 要考虑到边界情况即可.
AC Code

const int maxn = 1e5+5;
void solve()
{
    int ans = 0;
    for (int i = 100 ; i <= 100000 ; i ++) {
        int t = i;
        string s = "";
        while(t) {
            s += t%10 + '0';
            t /= 10;
        }
//        reverse(s.begin(), s.end()); // 效果是一样的..
        if (i == 98765) cout << s << endl;
        int j; int flag = 1;
        if (s[0] <= s[1]) flag = 0;
        for (j = 0 ; j + 1 < sz(s) && flag ; j ++) {
            if (s[j+1] > s[j]) break;
            if (s[j+1] == s[j]) {
                flag = 0;
                break;
            }
        }
        if (j+1 == sz(s)) flag = 0; // 这个边界情况要注意到!
        for (; j + 1 < sz(s) && flag; j ++) {
            if (s[j] >= s[j+1]) {
                flag = 0;
                break;
            }
        }
        if (flag) ++ans;
    }
    cout << ans << endl;
}

D: 简单dp, dp[i] 代表当前的a[i]作为最长上升子序列的最后一个元素的最优解, 转移方程就是dp[i] = max(dp[i], dp[j] + 1); 题目的f即dp数组.

ans: f[i] = max(f[i], f[j] + 1);

E: 这个全排列有点恶心, 首先找出这个问题要解决的最重要的问题是当有重复数字时怎么处理, 当然没有重复的可以直接dfs下去即可,但是有重复时我们要进行去重, 即不能搜重了….. 所以我们要判断如果当前要填的地方后面未填的有相同的并且标记过的, (注意代码的实现方法, 每次都是从头开始的),那么就要去掉这种情况即可.

ans : str[i] == str[j] && vis[j]

F: dfs随便搜一下即可.
AC Code

const int maxn = 15+5;
int a[maxn][maxn];
bool ok(int x, int y, int f) {
    for (int i = 0 ; i < 9 ; i ++) {
        if (a[i][y] == f || a[x][i] == f) return false;
    } // 去同一行同一列
    int r = x/3*3, c = y/3*3;
    for (int i = 0 ; i < 3 ; i ++) {
        for (int j = 0 ; j < 3 ; j ++) {
            if (a[i+r][j+c] == f) return false;
        }
    } // 去同一个九宫格
    return true;
}
void print_ans() {
    for (int i = 0 ; i < 9 ; i ++) {
        for (int j = 0 ; j < 9 ; j ++) {
            printf("%d%c", a[i][j], j == 8 ?'\n':' ');
        }
    }
}
int flag = 0;
void dfs(int x, int y) {
    if (flag) return ;
    if (x == 9 && y == 0) {
        print_ans();
        flag = 1;
        return ;
    }
    if (x >= 9) return ;
    if (y == 9) dfs(x+1, 0);
    else if (a[x][y]) dfs(x, y+1);
    else {
        for (int i = 1 ; i <= 9 ; i ++) {
            if (ok(x, y, i)) {
                a[x][y] = i;
                dfs(x, y+1);
                a[x][y] = 0;
            }
        }
    }
}
void solve()
{
    for (int i = 0 ; i < 9 ; i ++) { // 注意为了方便判断同一个九宫格的, 下标最好从0开始.
    // 这种处理要以后要注意下. 不要从1开始, 这样很难处理到... 小技巧.
        for (int j = 0 ; j < 9 ; j ++) {
            string s; cin >> s;
            if (s[0] != '*') a[i][j] = s[0]-'0';
        }
    }
    dfs(0, 0);
}

G: 我觉得这道题是这10道中最难的….. 确实没做出来, 唯一一道搜题解的….. 原来我的开始方向就想错了….. 我们要进行公式的转化, A(i+1) = 2*Ai - A(i-1) + 2Ci; 我们先不看Ci.
然后有
A2 = 2A1 - A0;
A3 = 2A2 - A1 = 3A1 - 2A0;
A4 = 2A3 - A2 = 4A1 - 3A0;
所以我们可以看出A(n+1) 就有(n+1) 个A1, 所以我们直接把A1初始化为0, 然后根据递推式一步一步推出A(n+1)。 等于多少 , 此时再用输入数据的A(n+1) - 我们推的A(n+1)。就等于(n+1)个A1的值, 然后除一下就是ans. 所以还是得转化下思维, 进行公式的演变…….

AC Code

const int maxn = 1e5+5;
db a[maxn];
void solve()
{
    int n; cin >> n;
    db tmp;
    cin >> a[0] >> tmp;
    a[1] = 0;
    for (int i = 2 ; i <= n + 1 ; i ++) {
        db c; cin >> c;
        a[i] = 2*a[i-1] - a[i-2] + 2*c;
    }
    db ans = (tmp - a[n+1])/(n+1);
    printf("%.2f\n", ans);
}

H: 直接对k对关系建边, 然后跑bfs即可.
AC Code

vector<int>g[maxn];
int vis[maxn];
int bfs(int st, int ed) {
    queue<pii>q; Fill(vis, 0);
    q.push({st, 0}); vis[st] = 1;
    while(!q.empty()) {
        pii u = q.front();
        if (u.fi == ed) {
            return u.se;
        }
        q.pop();

        for (int i = 0 ; i < sz(g[u.fi]) ; i ++) {
            int to = g[u.fi][i];
            if (vis[to]) continue;
            vis[to] = 1;
            q.push({to, u.se+1});
        }
    }
    return -1;
}
void solve()
{
    string s, t;
    cin >> s >> t;
    int n; cin >> n;
    for (int i = 1 ; i <= n ; i ++) {
        string a, b;
        cin >> a >> b;
        g[a[0]-'a'+1].pb(b[0]-'a'+1);
    }
    int ans = 0;
    for (int i = 0 ; i < sz(s) ; i ++) {
        int st = s[i]-'a'+1;
        int ed = t[i]-'a'+1;
        int tmp = bfs(st, ed);
        if (tmp == -1) {
            ans = -1;
            break;
        }
        ans += tmp;
    }
    cout << ans << endl;
}

I : 预处理下二维前缀和, 然后就可以O(1)的回答, 复杂度2000^2 + q;
AC Code

const int maxn = 2e3+5;
ll s[maxn][maxn], dp[maxn][maxn];
const int N = 2e3;
void solve()
{
    int n; scanf("%d", &n);
    for (int i = 1 ; i <= n ; i ++) {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        s[x][y] += w;
    }
    for (int i = 0 ; i <= N ; i ++) {
        for (int j = 0 ; j <= N ; j ++) {
            dp[i][j] += s[i][j];
            if (i == 0 && j == 0) continue;
            else if (i == 0) dp[i][j] += dp[i][j-1];
            else if (j == 0) dp[i][j] += dp[i-1][j];
            else {
                dp[i][j] += dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1];
            }
        }
    }
    int q; scanf("%d", &q);
    while(q--) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        ll ans = dp[x2][y2];
        if (x1 - 1 >= 0) ans -= dp[x1-1][y2];
        if (y1 - 1 >= 0) ans -= dp[x2][y1-1];
        if (x1-1 >= 0 && y1-1 >= 0) ans += dp[x1-1][y1-1];
        printf("%lld\n", ans);
    }
}

J: 对于有根树询问某点的所有子树问题一般就是dfs序 + 线段树. 然后就是为一个区间最大最小值, 最小值用于剪枝, 最大值用于算答案, 这样就可以保证复杂度又可以算ans.
AC Code

const int maxn = 1e5+5;
int cnt, head[maxn];
int n, root, ti;
int p1[maxn], p2[maxn], a[maxn];
struct node {
    int to,next;
}e[maxn<<1];
void init() {
    cnt = 0; Fill(head, -1);
}
void add(int u, int v) {
    e[cnt] = node{v, head[u]};
    head[u] = cnt++;
}
void dfs_id(int u, int fa)
{
    p1[u] = ++ti;
    a[ti] = u;
    for(int i = head[u] ; ~i ; i = e[i].next){
        int to = e[i].to;
        if (fa == to) continue;
        dfs_id(to, u);
    }
    p2[u] = ti;
}

struct Tree{
    int tl, tr; ll minn, maxx;
} tree[maxn<<2];

void pushup(int id)
{
    tree[id].maxx = max(tree[id<<1].maxx, tree[id<<1|1].maxx);
    tree[id].minn = min(tree[id<<1].minn, tree[id<<1|1].minn);
}

void build(int id, int l, int r)
{
    tree[id].tl = l; tree[id].tr = r;
    if(l == r){
        tree[id].minn = tree[id].maxx = a[l];
        return ;
    }
    int mid = (l+r) >> 1;
    build(id<<1, l, mid);
    build(id<<1|1, mid+1, r);
    pushup(id);
}

int ans;
void query(int id, int ql, int qr, int val)
{
    int l = tree[id].tl , r = tree[id].tr;
    if (tree[id].minn >= val) return ;
    if(ql <= l && r <= qr && tree[id].maxx < val) {
        ans += r - l + 1;
        return ;
    }
    if (l == r) return ;
    int mid = (l+r) >> 1 ;
    if(ql <= mid) query(id<<1, ql, qr, val);
    if(qr > mid) query(id<<1|1, ql, qr, val);
}

int b[maxn];
void solve()
{
    scanf("%d%d", &n, &root); init();
    for (int i = 1 ; i <= n-1 ; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    dfs_id(root, -1);
    build(1, 1, n);
    for (int i = 1 ; i <= n ; i ++) {
        ans = 0; query(1, p1[i], p2[i], i);
        b[i] = ans;
    }
    for (int i = 1 ; i <= n ; i ++) {
        printf("%d%c", b[i], i == n ?'\n':' ');
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值