A.Bad Ugly Numbers

题意:

构造一个长度为n的数字使得其不能被其中的每一位数整除。

题解:

除了n为1以外,其余构造2333333即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
char s[maxn];
void solve()
{
    int n;
    scanf("%d", &n);
    if (n == 1)
    {
        puts("-1");
        return;
    }
    putchar('2');
    for (int i = 1; i < n; i++)
        putchar('3');
    puts("");
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

B.Maximums

题意:

对于数组,数组满足,,数组满足。现在给定,要求反推

题解:

因为所以在遍历的同时,维护即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int main()
{
    int n;
    scanf("%d", &n);
    ll x = 0, b;
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &b);
        b += x;
        x = max(x, b);
        printf("%lld ", b);
    }
    puts("");
    return 0;
}

C.Permutation Partitions

题意:

给定一种的排列,现在让你分成块,求每块的最大值之和。形式上为,并算出有多少种分法可以达到这个最大值。

题解:

最大值就是的区间和,根据这k个数来划分区间即可,记录这k个数的下标,分法总数为

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    ll ans = 1, sum = 0, l = -1;
    for (int i = 1; i <= n; i++)
    {
        ll p;
        scanf("%lld", &p);
        if (p > n - k)
        {
            sum += p;
            if (l != -1)
                ans = ans * (i - l) % mod;
            l = i;
        }
    }
    printf("%lld %lld\n", sum, ans);
    return 0;
}

D.Prefix-Suffix Palindrome(马拉车)

题意:

给定串,从的前缀和后缀取任意长度进行拼接成新串,使得为回文串并尽可能长。

题解:

先双端扫描一遍,确定回文的前缀和后缀,获得左区间和右区间,再对中间部分分别正序和逆序跑一遍,最终答案就是左区间+中间部分的前缀和后缀较大者+右区间

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
string Manacher(const string &s)
{
    string t = "#";
    for (char c : s)
        t += c, t += "#";
    int RL[t.size()] = {0};
    int MaxRight = 0;
    int pos = 0;
    for (int i = 0; i < t.size(); i++)
    {
        if (i < MaxRight)
            RL[i] = min(RL[2 * pos - i], MaxRight - i);
        else
            RL[i] = 1;
        while (i - RL[i] >= 0 && i + RL[i] < t.size() && t[i - RL[i]] == t[i + RL[i]])
            RL[i] += 1;
        if (RL[i] + i - 1 > MaxRight)
            pos = i, MaxRight = RL[i] + i - 1;
    }
    int MaxLen = 0;
    for (int i = 0; i < t.size(); i++)
        if (RL[i] == i + 1)
            MaxLen = i;
    return s.substr(0, MaxLen);
}
void solve()
{
    string s;
    cin >> s;
    int l = 0, r = s.size() - 1;
    while (l < r && s[l] == s[r])
        ++l, --r;
    string s1 = s.substr(l, r - l + 1);
    string s2 = s1;
    reverse(s2.begin(), s2.end());
    s1 = Manacher(s1);
    s2 = Manacher(s2);
    cout << s.substr(0, l) << (s1.size() > s2.size() ? s1 : s2) << s.substr(r + 1) << "\n";
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
}

E.Bombs(线段树)

题意:

给定的排列,,将依次加入初始为空的集合的值表示第次加入的值为雷。若加入的是雷就把当前集合最大值从集合中移出(先加再移出)。现在规定对于每一个...都是雷。求对于每一个,操作后集合中的最大值。

题解:

首先雷越多,最大值一定不会变的更大,所以该序列一定为非递增序列。由于描述的是下标,所以我们关心加入集合的顺序。现在我们将从最大值开始遍历,若没有任何的雷,那么最大值一定为,现在我们确定一个最大值后,就要关注雷的位置,也就是什么时候会把这个最大值给出来。具体实现可以通过区间最大值来进行。首先将区间的最大值加一,对于位最大值为的条件为全区间最大值大于,当该位最大值确定后,我们就要将区间的最大值减一。区间最大值的维护用线段树即可。详细过程看代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
struct tree
{
    int mx, lazy;
} tr[maxn << 2];
int n, p[maxn], q[maxn], ans[maxn];
void pushdown(int rt)
{
    if (tr[rt].lazy)
    {
        tr[rt << 1].mx += tr[rt].lazy;
        tr[rt << 1].lazy += tr[rt].lazy;
        tr[rt << 1 | 1].mx += tr[rt].lazy;
        tr[rt << 1 | 1].lazy += tr[rt].lazy;
        tr[rt].lazy = 0;
    }
}
void pushup(int rt)
{
    tr[rt].mx = max(tr[rt << 1].mx, tr[rt << 1 | 1].mx);
}
void update(int rt, int l, int r, int L, int R, int val)
{
    if (L <= l && r <= R)
    {
        tr[rt].mx += val;
        tr[rt].lazy += val;
        return;
    }
    pushdown(rt);
    int mid = l + r >> 1;
    if (L <= mid)
        update(rt << 1, l, mid, L, R, val);
    if (R > mid)
        update(rt << 1 | 1, mid + 1, r, L, R, val);
    pushup(rt);
}
int main()
{
    scanf("%d", &n);
    for (int i = 1, x; i <= n; i++)
    {
        scanf("%d", &x);
        p[x] = i;
    }
    for (int i = 1; i <= n; i++)
        scanf("%d", &q[i]);
    int idx = 0;
    for (int i = n; i >= 1; i--)
    {
        update(1, 1, n, 1, p[i], 1);
        while (idx < n && tr[1].mx > 0)
        {
            idx++;
            ans[idx] = i;
            update(1, 1, n, 1, q[idx], -1);
        }
    }
    for (int i = 1; i <= n; i++)
        printf("%d ", ans[i]);
    puts("");
    return 0;
}