Confused-2019-BUPT校赛题解

2019BUPT题解

  • 前言
  • A.Sequence
  • B.Key
  • I.Poeroz&YYOJ
  • K.Candy&Magic

前言

由于OJ上还没有题没法测试,不保证代码准确,但是算法思想肯定是对的,等可以交的话通过后这句会删掉。
其他的题以后补。

A.Sequence

题目大意为给定 A,B 。需要判定是否存在一组数 l , r,使得区间内有 A 个奇数 B 个偶数。范围为1e18
是个水题。
很明显奇数偶数最多差一个,否则不是连续的。所以当 A,B 相差小于1 时输出 YES,否则为 NO
需要注意 A,B 同为 0 时输出 NO,并且测试样例较多需要用scanf或者开输入输出挂

//水

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define TI()  \
    int T;    \
    cin >> T; \
    while (T--)
    
int main()
{
    TI()
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        if (abs(a - b) > 1 || !(a || b)) {
            printf("NO\n");
        } else {
            printf("YES\n");
        }
    }
    return 0;
}

B.Key

题目大意为Bob想通过一条有n扇门的路,每经过一扇门需要一把钥匙,购买一把钥匙花费为1,门的种类不同也需要不同种钥匙,他可以在任何时间购买任一种钥匙,但最多携带k种钥匙。
开始考虑分段,即从当前往后考虑k种门,经过这k道门的花费为k-xx为此时拥有的钥匙中,和之后k种门种类相同的个数,即若当前拥有钥匙{1,2,3},后k种为{2,3,4},则只需丢掉钥匙1,购买钥匙4即可,答案为3-2=1
然后就WA到自闭。
最后快结束的时候ljg想到一个样例为{1,2,3,4,5,3,2,1}, k=3,发现这样跑下来答案为7,但是有更优答案为6。
所以这算法是假的!!!

之后换了贪心的思路 (也是官方题解),每次需要买钥匙的时候,丢掉距离当前位置最远使用的钥匙就可以了,比如上面样例在拥有钥匙{1,2,3}时碰到门4,判断出下一次用1是最远的,则丢掉1;拥有{2,3,4}碰到门5,判断出4之后不再使用 (距离记为inf) 丢掉4。
注意记录的下标总体最多 1e5,但需要动态存储否则会超内存。

// 思维+队列
//代码写好了补

//input
/*
3
6 2
1 2 3 1 3 4
10 3
1 2 3 5 1 3 2 4 2 1
5 3
1 2 3 4 5 3 2 1
*/

//output
/*
4
6
6
*/

I.Poeroz&YYOJ

题目大意为判定输入{A,C,W}构成的字符串是否合法,合法条件为:WA不能相连且AC至少出现一次

初见开始在想数位DP(因为前几天一直在看),后来发现是一个简单的递推;

状态 A1[i],C1[i],W1[i] 分别表示以 A,C,W 结尾长度为i且不存在WA的字符串的个数
状态 A2[i],C2[i],W2[i] 分别表示以 A,C,W 结尾长度为i且不存在WA和AC的字符串的个数

初始状态:

A1[1]=C1[1]=W1[1]=A2[1]=C2[1]=W2[1]=1;

转移公式为:

A1[i]=	A1[i-1]+C1[i-1]	;
C1[i]=	A1[i-1]+C1[i-1]+W[i-1];
W1[i]=	A1[i-1]+C1[i-1]+W[i-1];

A2[i]=	A2[i-1]+C2[i-1]	;
C2[i]=	C2[i-1]+W2[i-1];
W2[i]=	A2[i-1]+C2[i-1]+W2[i-1];

答案为长度为n,不存在WA且存在AC的状态数。
二者相减即可:

ans=A1[n]+C1[n]+W1[n]-(A2[n]+C2[n]+W2[n]);

O(n)跑一遍取模输出就可以了。
注意实现的时候不需要建6个数组来存,只需要12个变量重复赋值即可。

//递推

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;;
const int mod = (1e9 + 7);

int main()
{
    int n;
    ll a, _a, c, _c, w, _w;
    ll a1, _a1, c1, _c1, w1, _w1;
    
    while (cin >> n) {
        a = _a = c = _c = w = _w = 1;
        a1 = _a1 = c1 = _c1 = w1 = _w1 = 1;
        for (int i = 2; i <= n; i++) {
            a = (_a + _c) % mod;
            c = (_a + _c + _w) % mod;
            w = (_a + _c + _w) % mod;

            a1 = (_a1 + _c1) % mod;
            c1 = (_c1 + _w1) % mod;
            w1 = (_a1 + _c1 + _w1) % mod;

            _a = a, _c = c, _w = w;
            _a1 = a1, _c1 = c1, _w1 = w1;
        } //循环使用节省内存;
        cout << ((a + c + w) % mod - (a1 + c1 + w1) % mod + mod) % mod << endl;
    }
    return 0;
}
//input
/*
10
100
*/

//output
/*
11869
807464439
*/

K.Candy&Magic

题目大意为有一堆糖果,每个糖果有一个快乐值,小明想可以进行三步操作:

1.将一个糖果的值变为[-100,100]任意 和原值不同 的值;
2.将所有糖果按顺序放,规则为每次只能放到最上或者最下;
3.计算总值,规则为奇加偶减;

按顺序给定初始值,求结果最大为多少。
样例1:1 2 则将1变为-100 , 2 放在第一位,答案为 2-(-100)=102

分析
1.每次放到最上最下,那么每两个数必定有一个在奇数位一个在偶数位。设两个值为 a,b,对这两个数来说,摆放结果最大为|a-b|;
2.考虑改变a的值:a在奇数位,改变后结果为100-b;a在偶数位,结果为100+b;则无论a在何处,最大结果为100+|b|,所以对某一对来说,改变a的收益为100+|b|-|a-b|,所以需要改变这一对中绝对值小的那个值。要使收益最大化,需要将每一对按照收益排序,选择最合适的进行改变。
所以建立结构体储存值 (|a|<=|b|) ,输入时累加,编cmp函数用sort排序,或者标记一下最大收益的对,最后加上收益就是答案了。
需要注意,如果每一对都是{100,-100}的情况,因为要变成不同的,最后答案需要-1;
复杂度是 O(n) 级别的。
官方题解坐太后排没看清,但是说复杂度 O(n^3) 推测应该是DP 。

//贪心+思维
#include <bits/stdc++.h>
using namespace std;

struct Pro {
    int a, b, mabs;
} p[55];

bool cmp(Pro A, Pro B)
{
    int ans1 = 100 + abs(A.b) - A.mabs;
    int ans2 = 100 + abs(B.b) - B.mabs;
    return ans1 > ans2;
}

int main()
{
    int n;
    while (cin >> n) {
        int ans = 0;
        bool flag = true;
        for (int i = 0; i < n / 2; i++) {
            cin >> p[i].a >> p[i].b;
            if (abs(p[i].a) > abs(p[i].b)) {
                swap(p[i].a, p[i].b);
            }
            p[i].mabs = abs(p[i].a - p[i].b);
            ans += p[i].mabs;
            if ((p[i].mabs) != 200) {
                flag = false;
            }
        }
        sort(p, p + n / 2, cmp);
        ans += (100 + abs(p[0].b) - (p[0].mabs));
        if (flag)
            ans -= 1;
        cout << ans << endl;
    }
    return 0;
}

//input
/*
2 1 2
2 -1 -2
2 -1 2
4 100 -100 -100 100
4 100 100 100 -100
*/

//output
/*
102
102
399
400
*/

你可能感兴趣的:(ACM)