CodeTON Round 9 div 1+2 个人题解(A~E)

CodeTON Round 9 div 1+2 个人题解(A~E)

Dashboard - CodeTON Round 9 (Div. 1 + Div. 2, Rated, Prizes!) - Codeforces

火车头

#include <bits/stdc++.h>

using namespace std;

#define ft first
#define sd second

#define yes cout << "yes\n"
#define no cout << "no\n"

#define Yes cout << "Yes\n"
#define No cout << "No\n"

#define YES cout << "YES\n"
#define NO cout << "NO\n"

#define pb push_back
#define eb emplace_back

#define all(x) x.begin(), x.end()
#define all1(x) x.begin() + 1, x.end()
#define unq_all(x) x.erase(unique(all(x)), x.end())
#define unq_all1(x) x.erase(unique(all1(x)), x.end())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL

#define RED cout << "\033[91m"     // 红色
#define GREEN cout << "\033[92m"   // 绿色
#define YELLOW cout << "\033[93m"  // 蓝色
#define BLUE cout << "\033[94m"    // 品红
#define MAGENTA cout << "\033[95m" // 青色
#define CYAN cout << "\033[96m"    // 青色
#define RESET cout << "\033[0m"    // 重置

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// typedef __int128_t i128;

typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<string, ll> psl;

typedef tuple<int, int, int> ti3;
typedef tuple<ll, ll, ll> tl3;
typedef tuple<ld, ld, ld> tld3;

typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<vi> vvi;
typedef vector<vl> vvl;

// std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());

template <typename T>
inline T read()
{
    T x = 0;
    int y = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0')
    {
        if (ch == '-')
            y = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * y;
}

template <typename T>
inline void write(T x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x >= 10)
    {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

/*#####################################BEGIN#####################################*/
void solve()
{
}

int main()
{
    ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    std::cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 链接:

A. Shohag Loves Mod

Shohag 有一个整数 n n n。请帮他找出一个递增的整数序列 1 ≤ a 1 < a 2 < … < a n ≤ 100 1 \leq a_1 < a_2 < \ldots < a_n \leq 100 1a1<a2<<an100,使得 a i m o d    i ≠ a j m o d    j a_i \mod i \neq a_j \mod j aimodi=ajmodj 在所有 1 ≤ i < j ≤ n 1 \leq i < j \leq n 1i<jn 的对中都成立。

可以证明,在给定的约束下,总是存在这样的序列。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 50 1 \leq t \leq 50 1t50) — 测试用例数。
每个测试用例的第一行,也是唯一一行,包含一个整数 n n n ( 2 ≤ n ≤ 50 2 \leq n \leq 50 2n50)。

输出
对于每个测试用例,打印 n n n 个整数——满足语句中所述条件的整数序列。如果有多个这样的序列,则输出任意一个。

示例
输入

2
3
6

输出

2 7 8
2 3 32 35 69 95

注意
在第一个测试用例中,序列是递增的,值在 1 1 1 100 100 100 之间,并且每对索引满足语句中提到的条件:

对于对 ( 1 , 2 ) (1, 2) (1,2) a 1 m o d    1 = 2 m o d    1 = 0 a_1 \mod 1 = 2 \mod 1 = 0 a1mod1=2mod1=0 a 2 m o d    2 = 7 m o d    2 = 1 a_2 \mod 2 = 7 \mod 2 = 1 a2mod2=7mod2=1。所以它们是不同的。
对于对 ( 1 , 3 ) (1, 3) (1,3) a 1 m o d    1 = 2 m o d    1 = 0 a_1 \mod 1 = 2 \mod 1 = 0 a1mod1=2mod1=0 a 3 m o d    3 = 8 m o d    3 = 2 a_3 \mod 3 = 8 \mod 3 = 2 a3mod3=8mod3=2。所以它们是不同的。
对于对 ( 2 , 3 ) (2, 3) (2,3) a 2 m o d    2 = 7 m o d    2 = 1 a_2 \mod 2 = 7 \mod 2 = 1 a2mod2=7mod2=1 a 3 m o d    3 = 8 m o d    3 = 2 a_3 \mod 3 = 8 \mod 3 = 2 a3mod3=8mod3=2。所以它们是不同的。
请注意,您不必打印完全相同的序列,只要打印满足必要条件的任何其他序列即可。

解题思路

我们贪心的想,如果要让我们在后面限制尽可能的少,我们应该构建出 a i m o d    i = 0 , 1 , 2 , 3 , … a_i \mod i = 0,1,2,3,\dots aimodi=0,1,2,3, 这样的序列。

实际上就是 1 , 3 , 5 , 7 , … , 2 i − 1 1,3,5,7, \dots , 2i-1 1,3,5,7,,2i1

实现代码
void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cout << 2 * i - 1 << " \n"[i == n];
    }
}

B. Shohag Loves Strings

对于字符串 p p p,设 f ( p ) f(p) f(p) p p p 的唯一非空子串的个数。

Shohag 有一个字符串 s s s。请帮助他找到一个非空字符串 p p p,使得 p p p s s s 的子串,且 f ( p ) f(p) f(p) 是偶数,或者指出不存在这样的字符串。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含一个由小写英文字母组成的字符串 s s s ( 1 ≤ ∣ s ∣ ≤ 1 0 5 1 \leq |s| \leq 10^5 1s105)。
保证所有测试用例中 s s s 的长度总和不超过 3 ⋅ 1 0 5 3 \cdot 10^5 3105

输出
对于每个测试用例,打印一个满足语句中所述条件的非空字符串,如果不存在这样的字符串,则打印 − 1 -1 1。如果有多个解决方案,则输出任意一个。

示例
输入

5
dcabaac
a
youknowwho
codeforces
bangladesh

输出

abaa
-1
youknowwho
eforce
bang

注意
在第一个测试用例中,我们可以设 p = abaa p = \text{abaa} p=abaa,因为它是 s s s 的子串,且 p p p 的唯一非空子串有 a , b , a a , a b , b a , a b a , b a a a, b, aa, ab, ba, aba, baa a,b,aa,ab,ba,aba,baa a b a a abaa abaa,因此总共有 8 8 8 个不同的子串,这是偶数。

在第二个测试用例中,我们只能设 p = a p = a p=a,但它只有一个唯一非空子串,因此这个数字是奇数,不有效。

在第三个测试用例中,整个字符串包含 52 52 52 个不同的非空子串,因此字符串本身是一个有效的解决方案。

解题思路

观察发现

  1. 对于长度为 1 1 1 的子串:显然不符合条件。

  2. 对于长度为 2 2 2 的子串:

    • 如果两个字母相同,即形如 a a aa aa ,所有子串为: a , a a a,aa a,aa 。为偶数,符合条件。
    • 如果两个字母不同,即形如 a b ab ab ,所有子串为: a , b , a b a,b,ab a,b,ab 。为奇数,不符合条件。
  3. 对于长度为 3 3 3 的子串:

    • 如果存在连续两个字母相同,即形如 a a b aab aab a b b abb abb ,包含在情况 1 1 1 中。

    • 如果有两个字母相同但不连续,即形如 a b a aba aba ,所有子串为: a , b , a b , b a , a b a a,b,ab,ba,aba a,b,ab,ba,aba 。为奇数,不符合条件。

    • 如果三个字母都不同,即形如 a b c abc abc ,所有子串为: a , b , c , a b , b c , a b c a,b,c,ab,bc,abc a,b,c,ab,bc,abc 。为偶数,符合条件。

  4. 对于长度为 4 4 4 及以上的子串:被前三种情况涵盖

所以只需要检查字符串中是否存在形如 a a aa aa a b c abc abc 的子串即可。

实现代码
void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    if (n == 1)
    {
        cout << "-1\n";
        return;
    }

    for (int i = 1; i < n; i++)
    {
        if (s[i] == s[i - 1])
        {
            cout << s[i - 1] << s[i] << "\n";
            return;
        }
    }
    for (int i = 2; i < n; i++)
    {
        if (s[i] != s[i - 1] && s[i] != s[i - 2] && s[i - 1] != s[i - 2])
        {
            cout << s[i - 2] << s[i - 1] << s[i] << "\n";
            return;
        }
    }
    cout << "-1\n";
}

C1. Shohag Loves XOR (Easy Version)

这是问题的简单版本。两个版本的不同之处以粗体标出。只有两个版本的问题都解决了,才能进行破解。

Shohag 有两个整数 x x x m m m。帮他数出有多少个整数 1 ≤ y ≤ m 1 \leq y \leq m 1ym x ≠ y x \neq y x=y x ⊕ y x \oplus y xy整数除数,这些整数要么是 x x x,要么是 y y y,要么两者都是。这里的 ⊕ \oplus 是按位异或操作符。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含两个空格分隔的整数 x x x m m m ( 1 ≤ x ≤ 1 0 6 1 \leq x \leq 10^6 1x106, 1 ≤ m ≤ 1 0 18 1 \leq m \leq 10^{18} 1m1018)。
保证所有测试用例中 x x x 的总和不超过 1 0 7 10^7 107

输出
为每个测试用例打印一个整数,即合适的 y y y 个数。

示例
输入

5
6 9
5 7
2 3
6 4
4 1

输出

3
2
1
1
0

注意
在第一个测试用例中,对于 x = 6 x=6 x=6,在 1 1 1 m = 9 m=9 m=9 的整数中,有 3 3 3 个有效的 y y y,它们是 4 4 4 5 5 5 7 7 7

y = 4 y=4 y=4 是有效的,因为 x ⊕ y = 6 ⊕ 4 = 2 x \oplus y = 6 \oplus 4 = 2 xy=64=2,而 2 2 2 x = 6 x=6 x=6 y = 4 y=4 y=4 的除数。
y = 5 y=5 y=5 是有效的,因为 x ⊕ y = 6 ⊕ 5 = 3 x \oplus y = 6 \oplus 5 = 3 xy=65=3,而 3 3 3 x = 6 x=6 x=6 的除数。
y = 7 y=7 y=7 是有效的,因为 x ⊕ y = 6 ⊕ 7 = 1 x \oplus y = 6 \oplus 7 = 1 xy=67=1,而 1 1 1 x = 6 x=6 x=6 y = 7 y=7 y=7 的除数。
在第二个测试用例中,对于 x = 5 x=5 x=5,在 1 1 1 m = 7 m=7 m=7 的整数中,有 2 2 2 个有效的 y y y,它们是 4 4 4 6 6 6

y = 4 y=4 y=4 是有效的,因为 x ⊕ y = 5 ⊕ 4 = 1 x \oplus y = 5 \oplus 4 = 1 xy=54=1,而 1 1 1 x = 5 x=5 x=5 y = 4 y=4 y=4 的除数。
y = 6 y=6 y=6 是有效的,因为 x ⊕ y = 5 ⊕ 6 = 3 x \oplus y = 5 \oplus 6 = 3 xy=56=3,而 3 3 3 y = 6 y=6 y=6 的除数。

解题思路

我们可以预处理出所有 x x x 的因数,然后枚举这些因数 d d d ,计算出 $y=x \oplus d $ ,判断是否满足 KaTeX parse error: Undefined control sequence: \and at position 8: y\le m \̲a̲n̲d̲ ̲y\neq x

这样我们就获得了所有符合条件的 x x x 的因数数量 c n t 1 cnt1 cnt1

然后我们再枚举所有所有 y ≤ x y\le x yx 的数,统计出所有符合条件的 y y y 并去之前枚举过程中预计的符合条件的 y y y 做一下容斥即可。

实现代码
const int N = 1e6 + 5;
vi divi[N];

void getDivi()
{
    for (int i = 1; i < N; i++)
    {
        for (int j = i; j < N; j += i)
        {
            divi[j].pb(i);
        }
    }
}
void solve()
{
    ll x, m;
    cin >> x >> m;
    ll cnt1 = 0, cnt2 = 0, cnt12 = 0;
    for (auto &d : divi[x])
    {
        ll y = x ^ d;
        if (y >= 1 && y <= m && y != x)
        {
            cnt1++;
            if (y % d == 0)
                cnt12++;
        }
    }
    for (int d = 1; d <= x; d++)
    {
        ll y = x ^ d;
        if (y >= 1 && y <= m && y != x)
        {
            if (y % d == 0)
                cnt2++;
        }
    }
    ll ans = cnt1 + cnt2 - cnt12;
    cout << ans << "\n";
}

C2. Shohag Loves XOR (Hard Version)

这是问题的困难版本。两个版本之间的差异以粗体标出。只有两个版本的问题都解决了,才能进行破解。

Shohag 有两个整数 x x x m m m 。帮他数出 1 ≤ y ≤ m 1 \leq y \leq m 1ym 中, x ⊕ y x \oplus y xy 能被 x x x y y y 这两个数整除的整数的个数。这里的 ⊕ \oplus 是按位异或运算符。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含两个空格分隔的整数 x x x m m m ( 1 ≤ x ≤ 1 0 6 1 \leq x \leq 10^6 1x106, 1 ≤ m ≤ 1 0 18 1 \leq m \leq 10^{18} 1m1018)。
保证所有测试用例中 x x x 的总和不超过 1 0 7 10^7 107

输出
为每个测试用例打印一个整数,即合适的 y y y 个数。

示例
输入

5
7 10
2 3
6 4
1 6
4 1

输出

3
2
2
6
1

注意
在第一个测试用例中,对于 x = 7 x=7 x=7,在 1 1 1 m = 10 m=10 m=10 的整数中,有 3 3 3 个有效的 y y y,它们是 1 1 1 7 7 7 9 9 9

y = 1 y=1 y=1 是有效的,因为 x ⊕ y = 7 ⊕ 1 = 6 x \oplus y = 7 \oplus 1 = 6 xy=71=6,而 6 6 6 能被 y = 1 y=1 y=1 整除。
y = 7 y=7 y=7 是有效的,因为 x ⊕ y = 7 ⊕ 7 = 0 x \oplus y = 7 \oplus 7 = 0 xy=77=0,而 0 0 0 能被 x = 7 x=7 x=7 y = 7 y=7 y=7 整除。
y = 9 y=9 y=9 是有效的,因为 x ⊕ y = 7 ⊕ 9 = 14 x \oplus y = 7 \oplus 9 = 14 xy=79=14,而 14 14 14 能被 x = 7 x=7 x=7 整除。

解题思路

分析 x ⊕ y x \oplus y xy 是否能被 x x x y y y 或两者同时整除。

  1. x ⊕ y x \oplus y xy 能被 x x x 整除

z = x ⊕ y z = x \oplus y z=xy,则 y = z ⊕ x y = z \oplus x y=zx 。因为 z ⊕ x ≤ z + x z \oplus x \leq z + x zxz+x,在 z ≤ m z \leq m zm 时,几乎所有 z z z 都可行,所以数量为 ⌊ m − x x ⌋ \lfloor \frac{m - x}{x} \rfloor xmx

对于 p > m − x p > m - x p>mx,只需检查区间 ( m − x , m + x ] (m - x, m + x] (mx,m+x] 中的两个 x x x 的倍数。

  1. x ⊕ y x \oplus y xy 能被 y y y 整除

x < y x < y x<y 时, x ⊕ y < 2 y x \oplus y < 2y xy<2y,没有解。

x ≥ y x \geq y xy,遍历所有 y ≤ x y \leq x yx 的值,统计 x ⊕ y x \oplus y xy 能被 y y y 整除的数量即可。

  1. x ⊕ y x \oplus y xy 能被 x x x y y y 同时整除

这意味着 x ⊕ y x \oplus y xy 能被 lcm ( x , y ) \text{lcm}(x, y) lcm(x,y) 整除。当 x ≠ y x \neq y x=y 时, lcm ( x , y ) ≥ 2 ⋅ max ⁡ ( x , y ) \text{lcm}(x, y) \geq 2 \cdot \max(x, y) lcm(x,y)2max(x,y),而 x ⊕ y < 2 ⋅ max ⁡ ( x , y ) x \oplus y < 2 \cdot \max(x, y) xy<2max(x,y),所以没有解,只有在 y = x y = x y=x 时才会出现这种情况。

综上,答案为情况一的结果加上情况二的结果,再减去情况三的结果。

实现代码
void solve()
{
    ll x, m;
    cin >> x >> m;
    ll z = m - m % x;
    ll ans = z / x;
    if (x < z)
        ans--;
    if ((x ^ z) >= 1 && (x ^ z) <= m)
        ans++;
    if ((x ^ (z + x)) >= 1 && (x ^ (z + x)) <= m)
        ans++;
    if (x <= m)
        ans--;
    for (ll y = 1; y <= min(x, m); y++)
    {
        ans += ((x ^ y) % y == 0);
    }
    cout << ans << '\n';
}

D. Shohag Loves GCD

舒哈格有一个整数 n n n 和由 m m m 个唯一整数组成的集合 S S S。请帮他找出 最大的整数数组 ∗ \text{最大的整数数组}^* 最大的整数数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an,使得每个 1 ≤ i ≤ n 1 \leq i \leq n 1in a i ∈ S a_i \in S aiS gcd ⁡ ( i , j ) ≠ gcd ⁡ ( a i , a j ) \gcd(i,j) \neq \gcd(a_i,a_j) gcd(i,j)=gcd(ai,aj) 在所有 1 ≤ i < j ≤ n 1 \leq i < j \leq n 1i<jn 对中都满足,或者指出不存在这样的数组。

如果 a≠b,并且在 a 和 b 不同的第一个位置上,数组 a 的元素比 b 中的相应元素大,那么数组 a 在词法上比相同长度的数组 b 大。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104) - 测试用例数。

每个测试用例的第一行包含两个整数 n n n m m m ( 1 ≤ m ≤ n ≤ 1 0 5 1 \leq m \leq n \leq 10^5 1mn105)。

第二行包含 m m m 个唯一整数,按递增顺序排列,代表集合 S S S 的元素 ( 1 ≤ x ≤ n 1 \leq x \leq n 1xn 对于每个 x ∈ S x \in S xS)。

保证所有测试用例中 n n n 的总和不超过 3 ⋅ 1 0 5 3 \cdot 10^5 3105

输出
对于每个测试用例,如果没有解决方案,则打印 − 1 -1 1,否则打印 n n n 个整数——满足条件的词典上最大的整数数组。

示例
输入

3
6 3
3 4 6
1 1
1
2 1
2

输出

6 4 4 3 4 3
1
-1

注意
在第一个测试用例中,数组中的每个元素都属于给定的集合 S = { 3 , 4 , 6 } S=\{3,4,6\} S={3,4,6},并且数组的所有索引对满足必要条件。特别地,对于对 ( 2 , 3 ) (2,3) (2,3) gcd ⁡ ( 2 , 3 ) = a 1 = 6 \gcd(2,3)=a_1=6 gcd(2,3)=a1=6 gcd ⁡ ( a 2 , a 3 ) = gcd ⁡ ( 4 , 4 ) = 4 \gcd(a_2,a_3)=\gcd(4,4)=4 gcd(a2,a3)=gcd(4,4)=4,因此它们不相等。还有其他满足条件的数组,但这个数组在词典上是最大的。

在第三个测试用例中,不可能有解决方案,因为我们只能使用 a = [ 2 , 2 ] a=[2,2] a=[2,2],但对于这个数组,对于对 ( 1 , 2 ) (1,2) (1,2) gcd ⁡ ( 1 , 2 ) = a 1 = 2 \gcd(1,2)=a_1=2 gcd(1,2)=a1=2 gcd ⁡ ( a 1 , a 2 ) = gcd ⁡ ( 2 , 2 ) = 2 \gcd(a_1,a_2)=\gcd(2,2)=2 gcd(a1,a2)=gcd(2,2)=2,因此它们相等,这是不允许的!

解题思路

观察发现,对于 i = 1 i = 1 i=1 ,由于 gcd ⁡ ( k , 1 ) = 1 \gcd(k, 1) = 1 gcd(k,1)=1 , 对于任意整数 k k k ,我们可以得出结论:

若在位置 i = 1 i=1 i=1 位置填入最大值 s m s_m sm ,则在其它位置 j j j j ∣ 1 , j ≠ i j|1,j\neq i j∣1,j=i )的可填最大值为 s m − 1 s_{m-1} sm1

推广可得:对于任意位置 i i i,设其可填最大值 a i = s k a_i=s_k ai=skKaTeX parse error: Undefined control sequence: \and at position 12: \forall j|i\̲a̲n̲d̲ ̲j \neq i , a j < a i a_j\lt a_i aj<ai

因此对所有 i i i 做一个筛法即可。

实现代码
void solve()
{
    int n, m;
    cin >> n >> m;
    vi s(m);
    for (int i = 0; i < m; i++)
    {
        cin >> s[i];
    }
    vi a(n + 1, inf);
    a[1] = m - 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = i + i; j <= n; j += i)
        {
            a[j] = min(a[i] - 1, a[j]);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (a[i] < 0)
        {
            cout << "-1\n";
            return;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cout << s[a[i]] << " \n"[i == n];
    }
}

E. Shohag Loves Inversions

舒哈格有一个整数数组 a a a。最初为 a = [ 0 , 1 ] a=[0,1] a=[0,1]。他可以重复执行以下操作任意多次:

假设 k k k 是当前数组 a a a 中的倒数*的个数。将 k k k 插入 a a a 中的任意位置,包括开头或结尾。例如,如果 a = [ 4 , 6 , 2 , 4 ] a=[4,6,2,4] a=[4,6,2,4],那么反转数就是 k = 3 k=3 k=3。因此,肖哈格可以在运算后得到以下数组: [ 3 , 4 , 6 , 2 , 4 ] [3,4,6,2,4] [3,4,6,2,4] [ 4 , 3 , 6 , 2 , 4 ] [4,3,6,2,4] [4,3,6,2,4] [ 4 , 6 , 3 , 2 , 4 ] [4,6,3,2,4] [4,6,3,2,4] [ 4 , 6 , 2 , 3 , 4 ] [4,6,2,3,4] [4,6,2,3,4] [ 4 , 6 , 2 , 4 , 3 ] [4,6,2,4,3] [4,6,2,4,3]

在给定整数 n n n 的情况下,帮助肖哈格计算在进行运算后可以得到的长度为 n n n 的不同数组的个数,取模 998244353 998244353 998244353

  • 数组 a a a 中的反转数是指 i < j i < j i<j a i > a j a_i > a_j ai>aj 这样的一对索引 ( i , j ) (i, j) (i,j) 的个数。

输入
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1t104) - 测试用例数。

每个测试用例的第一行,也是唯一一行,包含一个整数 n n n ( 2 ≤ n ≤ 1 0 6 2 \leq n \leq 10^6 2n106)。

保证所有测试用例中 n n n 的总和不超过 1 0 6 10^6 106

输出
针对每个测试用例,输出一个整数——可能的数组数量取模 998244353 998244353 998244353

示例
输入

4
4
2
7
69

输出

5
1
682
325188814

注意
在第一个测试用例中,可以获得以下 5 5 5 个数组(插入的倒数计数以粗体显示):

[ 0 , 1 ] → [ 0 , 0 , 1 ] → [ 0 , 0 , 1 , 0 ] [0,1] \rightarrow [0,0,1] \rightarrow [0,0,1,0] [0,1][0,0,1][0,0,1,0]
[ 0 , 1 ] → [ 0 , 0 , 1 ] → [ 0 , 0 , 0 , 1 ] [0,1] \rightarrow [0,0,1] \rightarrow [0,0,0,1] [0,1][0,0,1][0,0,0,1]
[ 0 , 1 ] → [ 0 , 1 , 0 ] → [ 0 , 1 , 0 , 1 ] [0,1] \rightarrow [0,1,0] \rightarrow [0,1,0,1] [0,1][0,1,0][0,1,0,1]
[ 0 , 1 ] → [ 0 , 1 , 0 ] → [ 0 , 1 , 1 , 0 ] [0,1] \rightarrow [0,1,0] \rightarrow [0,1,1,0] [0,1][0,1,0][0,1,1,0]
[ 0 , 1 ] → [ 0 , 1 , 0 ] → [ 1 , 0 , 1 , 0 ] [0,1] \rightarrow [0,1,0] \rightarrow [1,0,1,0] [0,1][0,1,0][1,0,1,0]

解题思路

关键发现,由于初始数组的元素仅为 0 和 1,逆序对数量超过 1 时,当我们插入的值将大于数组中的任何元素。因此,我们可以通过这种方式来控制逆序对数量。

我们把逆序对数量大于 max ⁡ ( a ) \max(a) max(a) 的数组称为好数组,其它称为坏数组,假设当前正在进行转移,如果我们从好数组转移到坏数组,将带来很多复杂情况,容易导致重复计数。因此,我们应该设计出好数组到好数组的转移方程。

d p [ i ] dp[i] dp[i] 为当前数组长度为 i i i 时,得到长度为 n n n 的最终数组的数量,前提是当前数组为好数组。

设当前数组中的逆序对数量为 k k k,且 k > max ⁡ ( a ) k > \max(a) k>max(a)。那么:

  • 如果我们在末尾插入 k k k,那么新的逆序对数量仍将为 k k k。因此,如果我们在末尾插入 j j j k k k,并且在其他地方插入一次(有 i i i 种方式),那么我们将得到 d p i + j + 1 dp_{i+j+1} dpi+j+1 的情况。
  • 如果我们在末尾以外的地方插入 k k k,那么新的逆序对数量将超过 k k k,这将使我们得到 d p [ i + 1 ] dp[i+1] dp[i+1] 的相同情况。

因此, d p [ i ] = ( i ⋅ ∑ j > i d p [ j ] ) + 1 dp[i] = (i \cdot \sum_{j > i} dp[j]) + 1 dp[i]=(ij>idp[j])+1,这里的 1 1 1 是因为我们可以通过在末尾插入 n − i n - i ni k k k

现在我们只需处理初始数组转变为好数组的情况数量。

显然可以构造出 n − 1 n - 1 n1 种逆序对数量小于等于 1 的序列。它们的形式为 0 , 0 , … , 0 , [ 0 , 1 , 0 ] , 1 , … , 1 , 1 0, 0, \ldots, 0, [0, 1, 0], 1, \ldots, 1, 1 0,0,,0,[0,1,0],1,,1,1

考虑得到长度为 m m m 的好数组的方式,我们可以发现,只需要要在上面的序列中第一个 1 之前插入 1 即可获得一个好数组。

若第一个 1 的位置为 j j j,则我们有 j − 1 j - 1 j1 种方式。

因此,得到长度为 m m m 的好数组的方案数为:
∑ j = 2 m − 1 ( j − 1 ) = ( m − 2 ) ⋅ ( m − 1 ) 2 − 1 \sum_{j=2}^{m - 1} (j - 1) = \frac{(m - 2) \cdot (m - 1)}{2} - 1 j=2m1(j1)=2(m2)(m1)1

因此,答案就是:

n − 1 + ∑ m = 3 n ( ( m − 2 ) ⋅ ( m − 1 ) 2 − 1 ) ⋅ d p [ m ] n - 1 + \sum_{m=3}^{n} \left( \frac{(m - 2) \cdot (m - 1)}{2} - 1 \right) \cdot dp[m] n1+m=3n(2(m2)(m1)1)dp[m]

实现代码
const ll mod = 998244353;
void solve()
{
    ll n;
    cin >> n;
    ll sum = 0;
    vl dp(n + 1);
    for (ll i = n; i >= 1; i--)
    {
        dp[i] = (i * sum % mod + 1) % mod;
        sum = (sum + dp[i]) % mod;
    }
    ll ans = n - 1;
    for (ll k = 3; k <= n; k++)
    {
        ll t = ((k - 1) * (k - 2) / 2 - 1 + mod) % mod;
        ans = (ans + t * dp[k] % mod) % mod;
    }
    cout << ans << '\n';
}

数学场,一堆因数相关的题目。

c2折腾半天没写完,赛后才把情况讨论完。

封面画师id:竜崎いち

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值