牛客练习赛58

https://ac.nowcoder.com/acm/contest/4090#question

A、牛能和宝石

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int a[100005], b[100005];
int main()
{
    int n;
    sc("%d", &n);
    for (int i = 0; i < n; i++)
        sc("%d", &a[i]);
    for (int i = 0; i < n; i++)
        sc("%d", &b[i]);
    sort(a, a + n);
    sort(b, b + n, greater());
    int ans = -2e9;
    for (int i = 0; i < n; i++)
        ans = max(ans, a[i] + b[i]);
    pr("%d", ans);
}

B、牛妹和01串

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
char s[100005];
int main()
{
    sc("%s", s);
    int len = strlen(s);
    int q = 0, w = 0, ans = 0;
    for (int i = 0; i < len; i++)
    {
        if (s[i] == '0')
            q = 1;
        else
            w = 1;
        if (q == 1 && w == 1)
        {
            q = 0, w = 0, ans++;
        }
    }
    pr("%d", ans);
}

C、矩阵消除游戏

状态压缩枚举,然后sort找最大。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int n, m, k;
ll a[20][20];
ll heng[20], t[20];
int main()
{
    sc("%d%d%d", &n, &m, &k);
    k = min(k, min(n, m));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
        {
            sc("%lld", &a[i][j]);
            heng[j] += a[i][j];
        }
    ll res = 0;
    for (int i = 0; i < (1 << n); i++)
    {
        ll ans = 0;
        for (int j = 0; j < m; j++)
            t[j] = heng[j];
        int cnt = 0;
        for (int j = 0; j < n; j++)
        {
            if (i & (1 << j))
            {
                cnt++;
                for (int k = 0; k < m; k++)
                {
                    ans += a[j][k];
                    t[k] -= a[j][k];
                }
            }
        }
        if (k - cnt < 0)
            continue;
        sort(t, t + m, greater());
        for (int i = 0; i < min(k - cnt, m); i++)
            ans += t[i];
        res = max(res, ans);
    }
    pr("%lld", res);
}

D、迷宫

dp,考虑每个位置只能由左边和上面转移过来,左边直接转移,上面的需要判断要不要放墙壁转移。

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int a[1005][1005];
int dp[1005][1005];
char s[1005];
int main()
{
    int n, m;
    sc("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        sc("%s", s + 1);
        for (int j = 1; j <= m; j++)
            a[i][j] = s[j] - '0';
    }
    for (int i = 0; i < 1005; i++)
        for (int j = 0; j < 1005; j++)
            dp[i][j] = 1e9;
    dp[1][1] = 0;
    for (int j = 2; j <= m; j++)
    {
        if (a[1][j] == 0 && a[1][j - 1] == 0)
            dp[1][j] = 0;
        else
            break;
    }
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i][j] == 0)
            {
                if (a[i][j - 1] == 0)
                    dp[i][j] = dp[i][j - 1];
                if (a[i - 1][j] == 0)
                {
                    if (a[i - 1][j + 1] == 1 || j == m)
                        dp[i][j] = min(dp[i][j], dp[i - 1][j]);
                    else
                        dp[i][j] = min(dp[i][j], dp[i - 1][j] + 1);
                }
            }
        }
    }
    if (dp[n][m] > 1e8)
        dp[n][m] = -1;
    pr("%d\n", dp[n][m]);
}

E、最大GCD

每个数字最多 \sqrt{(10^5)} 个因数,所以存下一个因子有多少个数字是他的倍数并记录下下标不会内存超限。

对于每个询问,从大到小枚举 X 的因子,然后判断区间 [l, r] 内是否存在这个因子就可以了。

复杂度 O(n \sqrt n log \sqrt n) 

#include 
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
int a[100005];
vectorv[100005];//v[i] 表示含有因子 i 的数的位置
int main()
{
    int n, q;
    sc("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
    {
        sc("%d", &a[i]);
        int sqrtn = sqrt(a[i]);
        for (int j = 1; j <= sqrtn; j++)
        {
            if (a[i] % j == 0)
            {
                if (j * j == a[i])
                    v[j].push_back(i);
                else
                {
                    v[j].push_back(i);
                    v[a[i] / j].push_back(i);
                }
            }
        }
    }
    for (int i = 1; i <= q; i++)
    {
        int l, r, x;
        sc("%d%d%d", &l, &r, &x);
        int sqrtx = sqrt(x);
        int ans = 0;
        vectoryinzi;
        for (int j = 1; j <= sqrtx; j++)
        {
            if (x % j == 0)
            {
                if (j * j == x)
                    yinzi.push_back(j);
                else
                {
                    yinzi.push_back(j);
                    yinzi.push_back(x / j);
                }
            }
        }
        sort(yinzi.begin(), yinzi.end(), greater());
        //枚举 x 的因子并且按照从大到小排序
        for (auto t : yinzi)
        {
            int len = v[t].size();
            if (len == 0)
                continue;
            auto itl = lower_bound(v[t].begin(), v[t].end(), l);
            auto itr = upper_bound(v[t].begin(), v[t].end(), r);
            if (itr == v[t].begin())
                continue;
            itr--;
            if (itl <= itr)//二分判断[l,r]是否存在这个因子
            {
                ans = t;
                break;
            }
        }
        pr("%d\n", ans);
    }
}

F、XOR TREE

显然树剖,枚举一下长度对答案的影响发现区间长度为奇数时,间隔一个数字取一个数字,偶数时,整个区间都取。

与一般树剖线段树不同的是,这里多了一个询问时间隔一个数字取一个数字。

在这里我们考虑树的深度,显然,在树上移动一个单位,深度一定会对应的加一或者减一,也就是奇偶发生变化,所以我们可以考虑利用深度将一颗线段树分成两颗,分别维护深度为奇数和偶数,就可以解决这个问题了。

#include 
#define ll long long
#define sc scanf
#define pr printf
#define lson left,mid,k<<1
#define rson mid+1,right,k<<1|1
#define imid int mid=(left+right)>>1;
using namespace std;
const int MAXN = 2e5 + 5;
struct edge
{
    int to;
    int nex;
}e[MAXN * 2];
int head[MAXN], tot;
void add(int a, int b)
{
    e[tot] = edge{ b,head[a] };
    head[a] = tot++;
}
int fa[MAXN], sz[MAXN], deep[MAXN], son[MAXN];
int top[MAXN], p[MAXN], fp[MAXN];
int pos;
void init()
{
    memset(son, -1, sizeof son);
    pos = 1;
    memset(head, -1, sizeof head);
    tot = 1;
}
void dfs1(int u, int f)
{
    sz[u] = 1;
    fa[u] = f;
    deep[u] = deep[f] + 1;
    for (int i = head[u]; i + 1; i = e[i].nex)
    {
        int v = e[i].to;
        if (v == f)
            continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if (son[u] == -1 || sz[son[u]] < sz[v])
            son[u] = v;
    }
}
void dfs2(int u, int tp)
{
    top[u] = tp;
    p[u] = pos;
    fp[pos++] = u;
    if (son[u] == -1)
        return;
    dfs2(son[u], tp);
    for (int i = head[u]; i + 1; i = e[i].nex)
    {
        int v = e[i].to;
        if (v == son[u] || v == fa[u])
            continue;
        dfs2(v, v);
    }
}
struct node
{
    int l;
    int r;
    ll sum;
}que[2][MAXN * 4];
ll a[MAXN];
void up(int k, int op)
{
    que[op][k].sum = que[op][k << 1].sum ^ que[op][k << 1 | 1].sum;
}
void build(int left, int right, int k, int op)
{
    que[op][k].l = left;
    que[op][k].r = right;
    if (left == right)
    {
        if ((deep[fp[left]] & 1) == (op & 1))
            que[op][k].sum = a[fp[left]];
        else
            que[op][k].sum = 0;
        return;
    }
    imid;
    build(lson, op);
    build(rson, op);
    up(k, op);
}
void update(int left, int right, int k, int pos, ll val, int op)
{
    if (left == right)
    {
        que[op][k].sum = val;
        return;
    }
    imid;
    if (pos <= mid)
        update(lson, pos, val, op);
    else
        update(rson, pos, val, op);
    up(k, op);
}
ll query(int left, int right, int k, int ql, int qr, int op)
{
    if (qr < left || right < ql)
        return 0;
    if (ql <= left && right <= qr)
        return que[op][k].sum;
    imid;
    return query(lson, ql, qr, op) ^ query(rson, ql, qr, op);
}
 
int n, q;
void change1(int u, ll v)
{
    update(1, n, 1, p[u], v, deep[u] & 1);
}
ll change2(int u, int v)
{
    if (((deep[u] - deep[v]) & 1) == 1)
    {
        ll ans = 0;
        int f1 = top[u], f2 = top[v];
        while (f1 != f2)
        {
            if (deep[f1] < deep[f2])
            {
                swap(f1, f2);
                swap(u, v);
            }
            ans ^= query(1, n, 1, p[f1], p[u], 0);
            ans ^= query(1, n, 1, p[f1], p[u], 1);
            u = fa[f1];
            f1 = top[u];
        }
        if (deep[u] > deep[v])
            swap(u, v);
        ans ^= query(1, n, 1, p[u], p[v], 0);
        ans ^= query(1, n, 1, p[u], p[v], 1);
        return ans;
    }
    else
    {
        int op = (deep[u] + 1) % 2;
        ll ans = 0;
        int f1 = top[u], f2 = top[v];
        while (f1 != f2)
        {
            if (deep[f1] < deep[f2])
            {
                swap(f1, f2);
                swap(u, v);
            }
            ans ^= query(1, n, 1, p[f1], p[u], op);
            u = fa[f1];
            f1 = top[u];
        }
        if (deep[u] > deep[v])
            swap(u, v);
        ans ^= query(1, n, 1, p[u], p[v], op);
        return ans;
    }
}
 
ll read()
{
    ll x = 0;
    char c = getchar();
    while (c < '0' || c>'9') c = getchar();
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0', c = getchar();
    return x;
}
 
int main()
{
    init();
    n = read(); q = read(); //sc("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        a[i] = read(); //sc("%lld", &a[i]);
    for (int i = 1; i < n; i++)
    {
        int q, w;
        q = read(), w = read(); //sc("%d%d", &q, &w);
        add(q, w);
        add(w, q);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    build(1, n, 1, 0);
    build(1, n, 1, 1);
    while (q--)
    {
        int op, u; ll v;
        op = read(); u = read(); v = read(); //sc("%d%d%lld", &op, &u, &v);
        if (op == 1)//update
        {
            change1(u, v);
        }
        else//ans
        {
            pr("%lld\n", change2(u, v));
        }
    }
}
/*
5 3
1 2 3 4 5
1 2
2 3
3 4
4 5
2 1 5
1 2 8
2 1 5
 
1 2 3 4 5
4 4 3 2 1
  3 3 2 1
    2 2 1
      1 1
 
4 7 8 7 4
0 1 0 1 0
 
 
1 2 3 4 5 6
5 5 4 3 2 1
  4 4 3 2 1
    3 3 2 1
      2 2 1
        1 1
 
5 7 11 11 7 5
1 1 1 1 1 1
 
*/

 

你可能感兴趣的:(牛客网)