2018 保研复试上机

A,B

签到题

C

题意:简单博弈 

D

题意:有 1...n 的连续点,每个点你可以用固定数量的花费ci买固定数量的票ni,每向前走一个点需要花费一张票,初始在1点,没有票,问到达n点的最小花费。

思路:反向考虑,dp[i]表示从i点走到n点的最小花费,在i点时是没有票的。

   dp转移dp[i] = ci + min{dp[i+1],dp[i+2],...dp[i+ni]}

   min 部分用线段树单点修改,区间查询最小值优化。

E

题意:求区间LR中大于等于a,并且小于等于b的数的数量。

思路:简单主席树。

#include <bits/stdc++.h>
using namespace std;
#define N 100005
#define mid ((l+r)>>1)
#define lc (tr[d].ch[0])
#define rc (tr[d].ch[1])

struct Tr{
    int cnt,ch[2];
}tr[N<<2];
int cnt = 0,ro[N];
int newnode(){
    ++cnt;
    tr[cnt].cnt = 0,tr[cnt].ch[0] = tr[cnt].ch[1] = 0;
    return cnt;
}
int build(int l,int r,int pre,int pos){
    int d = newnode();
    tr[d].cnt = tr[pre].cnt + 1;
    if(l == r) return d;
    lc = tr[pre].ch[0],rc = tr[pre].ch[1];
    if(pos <= mid)
        lc = build(l,mid,tr[pre].ch[0],pos);
    else rc = build(mid+1,r,tr[pre].ch[1],pos);
    return d;
}

int query(int l,int r,int L,int R,int ro1,int ro2){
    if(L == l && R == r){
        return tr[ro2].cnt - tr[ro1].cnt;
    }
    if(R <= mid) return query(l,mid,L,R,tr[ro1].ch[0],tr[ro2].ch[0]);
    if(L > mid) return query(mid+1,r,L,R,tr[ro1].ch[1],tr[ro2].ch[1]);
    return query(l,mid,L,mid,tr[ro1].ch[0],tr[ro2].ch[0]) + query(mid+1,r,mid+1,R,tr[ro1].ch[1],tr[ro2].ch[1]);
}

int main()
{
    int n,m;
    cin >> n >> m;
    int a,b;
    for(int i = 1;i <= n;++i) scanf("%d",&a),ro[i] = build(1,1000000,ro[i-1],a);
    int L,R;
    for(int i = 1;i <= m;++i){
        scanf("%d%d%d%d",&a,&b,&L,&R);
        printf("%d
",query(1,1000000,a,b,ro[L-1],ro[R]));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/solvit/p/9627426.html