1.23 高一期末总结

%%%Aurora!!! 向神真的强,每逢大考必AK!!!

话说这次考试不讲武德,看了半天发现没有dp?

T1:NKOJ5837 基因中有AC

题面:人类基因由碱基'A','C','G','T'构成。
何老板检查了一下自己的DNA,拿到了检查报告。
检测报告里有一段长度为N的由字母'A','C','G','T'构成的表示基因片段的字符串。
何老板发现,自己的基因中带了很多“AC”,众所周知他的口号是“Life is short,AC more!”,于是他想知道对于该基因片段中的任意一段区间[L,R]中,出现了多少次“AC”,请你快速帮他做出回答。

题解:我一拿到这个题就感觉我做过,一开始写了个前缀和结果写挂了,后面用树状数组,结果是我的端点处理错了???wtclwtcl。

#pragma GCC optimize(3)

#include <bits/stdc++.h>

using namespace std;

#define re register 

char ch[200005];

int c[200005];
int n, q;

void modify(int x)
{
    for (int i = x; i <= n; i += (i & -i)) c[i]++;
}

int query(int x)
{
    int ans = 0;
    for (int i = x; i; i -= (i & -i)) ans += c[i];
    return ans;
}

int main()
{
    scanf("%d%d", &n, &q);
    scanf("%s", ch + 1);
//    if (ch[1] == 'A') mark[1] = 1;
    for (re int i = 2; i <= n; i++)
    {
        if (ch[i] == 'C' && ch[i - 1] == 'A')
        {
            modify(i);
        }
    }
    for (re int i = 1, l, r; i <= q; i++)
    {
        scanf("%d%d", &l, &r);
        printf("%d\n", query(r) - query(l));
    }
}

T2:NKOJ5811 奥特曼打怪

题面:

何老板最近在玩一款打怪兽的游戏,游戏虽然简单,他仍乐此不疲。

游戏中,何老板操控奥特曼与N只怪兽作战。每只怪兽都有一定的生命值,第i只怪兽的生命值为hi。
奥特曼可以发射光弹,何老板可以控制奥特曼往一只指定的怪兽发射光弹。怪兽被光弹击中后会损失A单位的生命值。该怪兽被击中的同时,光弹会发生爆炸,使得其他所有怪兽都损失B的生命值。
何老板想知道,奥特曼最少发射几次光弹,就能消灭所有怪兽(怪兽的生命值小于等于0,就被消灭了)。

 题解:我是真的菜啊。这个题要二分发射光弹的次数然后验证,结果我直接以权值建了个堆硬跑,,,活该我挂了。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

ll n, a, b, h[1000005];

bool check(ll x)
{
    ll cnt = 0;
    for (ll i = 1; i <= n; i++)
    {
        ll hh = h[i];
        hh -= b * x;
        if (hh <= 0) continue;
        else cnt += ((hh - 1) / a + 1);
        if (cnt > x) return 0;
    }
    return 1;
}

//ll h[1000005];

main()
{
    ll maxh = 0;
    scanf("%lld%d%d", &n, &a, &b); a -= b;
    for (ll i = 1; i <= n; i++)
    {
        scanf("%lld", &h[i]); maxh = max(maxh, h[i]);
    }
    ll l = 1, r = maxh, mid, ans;
    while (l <= r) 
    {
        if (check(mid = l + r >> 1)) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    printf("%lld", ans);
}

T3:NKOJ5832 老板砍树

题面:

何老板家门前有一排树,共 3 * N 棵 ,每棵树都有一定的高度,第i棵树高度为hi。

何老板需要添置家具,他雇你砍掉其中N棵树,剩下2*N棵。你可以砍掉其中任意N棵树,但何老板有个奇怪的要求,他希望剩下的树中,前N棵树的高度总和与后N棵树的高度总和之差,尽可能大。
请你计算出这个最大差值。

题解:这个题没什么好说的,把前n个数和后n个数分别用小根堆和大根堆存起来,然后中间n棵树用类似后悔堆的方法调整最优值即可。

#include <bits/stdc++.h>

using namespace std;

#define ll long long

priority_queue <ll, vector<ll>, greater<ll> > P;
priority_queue <ll> Q;

ll a[300005], sum[300005], mini[300005];

main()
{
    ll n;
    scanf("%lld", &n);
    for (ll i = 1; i <= 3 * n; i++)
    {
        scanf("%lld", &a[i]);
    }
    for (ll i = 1; i <= 2 * n; i++)
    {
        sum[i] = sum[i - 1];
        if (P.size() < n) P.push(a[i]), sum[i] += a[i];
        else if (a[i] > P.top())
        {
            sum[i] -= P.top(), sum[i] += a[i];
            P.pop(); P.push(a[i]);
        }
    }
    for (ll i = 3 * n; i > n; i--)
    {
        mini[i] = mini[i + 1];
        if (Q.size() < n) Q.push(a[i]), mini[i] += a[i];
        else if (a[i] < Q.top())
        {
            mini[i] -= Q.top(), mini[i] += a[i];
            Q.pop(); Q.push(a[i]);
        }
    }
    ll ans = -0x3f3f3f3f3f3f3f3f;
    for (ll i = n; i <= 2 * n; i++)
    {
        ans = max(ans, sum[i] - mini[i + 1]);
    }
    printf("%lld", ans);
}

T4:NKOJ5810 平均身高

题面:

NK信竞队有N名队员。
因要参加一年一度的全校自编操比赛,何老板组织队员们进行排练。
N名队员站成一排,从左往右身高分别是a1,a2,...,aN。

何老板设计了一个炫酷的加分动作。需要选相邻的若干同学出来(连续一段同学)出来表演。但要求选出的这些同学的平均身高需要大于等于K。

何老板想知道,他总共有多少种选择方案。

概括:给出一个整数序列,需要从中选出一个连续子序列,使得该序列的平均值不小于k,求方案数。

题解:将所有人的身高各减去k,这个题就转化为了求一段子序列的和大于0,于是问题转化为了求顺序对。PS:此题规模较大,需要离散化。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll n, k;
ll c[1000005], a[1000005], sum[1000005];

void modify(ll x)
{
    for (ll i = x; i <= n; i += (i & -i)) c[i]++;
}

ll query(ll x)
{
    ll ans = 0;
    for (ll i = x; i; i -= (i & -i)) ans += c[i];
    return ans;
}

main()
{
    ll ans = 0;
    scanf("%lld%lld", &n, &k);
    for (ll i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]), a[i] -= k;
    }
    for (ll i = 1; i <= n; i++)
    {
        sum[i] = sum[i - 1] + a[i];
        ans += ((a[i] += a[i - 1]) >= 0);
    }
    sort(sum + 1, sum + n + 1);
    ll tot = unique(sum + 1, sum + n + 1) - sum - 1;
    for (ll i = 1; i <= n; i++) a[i] = lower_bound(sum + 1, sum + tot + 1, a[i]) - sum;
    for (ll i = 1; i <= n; i++)
    {
        ans += query(a[i]);
        modify(a[i]);
    }
    printf("%lld", ans);
}

T5:NKOJ5831 作业积分

题面:

 

题解:真的淦,我直接贪难度大小能得50分hhh。其实是这么个思路,优先贪难度,记录题的种类,显然这k道题中每类题第一次出现的那道显然不会被替换,剩下的放在一个小根堆里,再讨论后面的题。如果后面的题出现了新的类型就替换,并且与当前最优值比较,于是就能保证最后得到的是最优值。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

bool mark[1000005];

struct node {
    ll a, w;
    bool operator< (node x) const {
        return w > x.w;
    }
}e[1000005];

//inline bool cmp(node x, node y) {return x.w < y.w;}

priority_queue <node> Q;

main()
{
    ll n, k;
    scanf("%lld%lld", &n, &k);
    for (ll i = 1; i <= n; i++)
    {
        scanf("%lld%lld", &e[i].a, &e[i].w);
    }
    sort(e + 1, e + n + 1);
    ll ans = 0, cnt = 0, sum = 0;
    for (ll i = 1; i <= n; i++)
    {
        if (i <= k) 
        {
            sum += e[i].w;
            if (!mark[e[i].a]) cnt++, mark[e[i].a] = 1;
            else Q.push(e[i]);
            ans = max(ans, sum + cnt * cnt);
        }
        else
        {
            if (Q.empty()) break;
            if (mark[e[i].a]) continue;
            mark[e[i].a] = 1, cnt++;
            sum -= Q.top().w, Q.pop();
            sum += e[i].w;
            ans = max(ans, sum + cnt * cnt);
        }
    }
    printf("%lld", ans);
}

T6:NKOJ4922 猜球游戏

题面:

 

 题解:hhh老板昨天告诉我们今天必考最小生成树,我看前五道题与最小生成树毫无关联,就想这个题是不是,没想到还真干出来了。

首先我们知道第0个杯子下没有小球,又有性质:知道[A,B-1]和[A,C]的奇偶性就能知道[B,C]的奇偶性,于是询问[L,R]的奇偶性实际上就是给L-1和R连一条权值为cij的边,最终只需要让所有点与0号店相连即可。所以这个题可以跑最小生成树。

#include <bits/stdc++.h>

using namespace std;

struct node {
    int u, v, w;
    bool operator< (node x) const {
        return w < x.w;
    }
}e[4000005];
int tot, sum;
int n;
inline void add_e(int x, int y, int z) {e[++tot].u = x; e[tot].v = y; e[tot].w = z;}

int fa[4000005];

int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}

void init()
{
    for (int i = 1; i <= n; i++) fa[i] = i;
}

void Kruskal()
{
    init();
    int cnt = 0;
    for (int i = 1; i <= tot; i++)
    {
        int fx = find(e[i].u), fy = find(e[i].v);
        if (fx == fy) continue;
        fa[fx] = fy;
        sum += e[i].w;
        if (++cnt == n) break;
    }
    printf("%d", sum);
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        for (int j = i, x; j <= n; j++)
        {
            scanf("%d", &x);
            add_e(i - 1, j, x);
        }
    }
    sort(e + 1, e + tot + 1);
    Kruskal();
}

 

posted @ 2021-01-23 22:33  Chasing-Dreams  阅读(267)  评论(1)    收藏  举报