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 1≤a1<a2<…<an≤100,使得 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 1≤i<j≤n 的对中都成立。
可以证明,在给定的约束下,总是存在这样的序列。
输入
第一行包含一个整数
t
t
t (
1
≤
t
≤
50
1 \leq t \leq 50
1≤t≤50) — 测试用例数。
每个测试用例的第一行,也是唯一一行,包含一个整数
n
n
n (
2
≤
n
≤
50
2 \leq n \leq 50
2≤n≤50)。
输出
对于每个测试用例,打印
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,…,2i−1
实现代码
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
1≤t≤104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含一个由小写英文字母组成的字符串
s
s
s (
1
≤
∣
s
∣
≤
1
0
5
1 \leq |s| \leq 10^5
1≤∣s∣≤105)。
保证所有测试用例中
s
s
s 的长度总和不超过
3
⋅
1
0
5
3 \cdot 10^5
3⋅105。
输出
对于每个测试用例,打印一个满足语句中所述条件的非空字符串,如果不存在这样的字符串,则打印
−
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 的子串:显然不符合条件。
-
对于长度为 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 的子串:
-
如果存在连续两个字母相同,即形如 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 及以上的子串:被前三种情况涵盖
所以只需要检查字符串中是否存在形如 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 1≤y≤m 是 x ≠ y x \neq y x=y 和 x ⊕ y x \oplus y x⊕y 的整数除数,这些整数要么是 x x x,要么是 y y y,要么两者都是。这里的 ⊕ \oplus ⊕ 是按位异或操作符。
输入
第一行包含一个整数
t
t
t (
1
≤
t
≤
1
0
4
1 \leq t \leq 10^4
1≤t≤104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含两个空格分隔的整数
x
x
x 和
m
m
m (
1
≤
x
≤
1
0
6
1 \leq x \leq 10^6
1≤x≤106,
1
≤
m
≤
1
0
18
1 \leq m \leq 10^{18}
1≤m≤1018)。
保证所有测试用例中
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
x⊕y=6⊕4=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
x⊕y=6⊕5=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
x⊕y=6⊕7=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
x⊕y=5⊕4=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
x⊕y=5⊕6=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 y≤x 的数,统计出所有符合条件的 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 1≤y≤m 中, x ⊕ y x \oplus y x⊕y 能被 x x x 或 y y y 这两个数整除的整数的个数。这里的 ⊕ \oplus ⊕ 是按位异或运算符。
输入
第一行包含一个整数
t
t
t (
1
≤
t
≤
1
0
4
1 \leq t \leq 10^4
1≤t≤104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含两个空格分隔的整数
x
x
x 和
m
m
m (
1
≤
x
≤
1
0
6
1 \leq x \leq 10^6
1≤x≤106,
1
≤
m
≤
1
0
18
1 \leq m \leq 10^{18}
1≤m≤1018)。
保证所有测试用例中
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
x⊕y=7⊕1=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
x⊕y=7⊕7=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
x⊕y=7⊕9=14,而
14
14
14 能被
x
=
7
x=7
x=7 整除。
解题思路
分析 x ⊕ y x \oplus y x⊕y 是否能被 x x x、 y y y 或两者同时整除。
- x ⊕ y x \oplus y x⊕y 能被 x x x 整除
设 z = x ⊕ y z = x \oplus y z=x⊕y,则 y = z ⊕ x y = z \oplus x y=z⊕x 。因为 z ⊕ x ≤ z + x z \oplus x \leq z + x z⊕x≤z+x,在 z ≤ m z \leq m z≤m 时,几乎所有 z z z 都可行,所以数量为 ⌊ m − x x ⌋ \lfloor \frac{m - x}{x} \rfloor ⌊xm−x⌋。
对于 p > m − x p > m - x p>m−x,只需检查区间 ( m − x , m + x ] (m - x, m + x] (m−x,m+x] 中的两个 x x x 的倍数。
- x ⊕ y x \oplus y x⊕y 能被 y y y 整除
当 x < y x < y x<y 时, x ⊕ y < 2 y x \oplus y < 2y x⊕y<2y,没有解。
当 x ≥ y x \geq y x≥y,遍历所有 y ≤ x y \leq x y≤x 的值,统计 x ⊕ y x \oplus y x⊕y 能被 y y y 整除的数量即可。
- x ⊕ y x \oplus y x⊕y 能被 x x x 和 y y y 同时整除
这意味着 x ⊕ y x \oplus y x⊕y 能被 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)≥2⋅max(x,y),而 x ⊕ y < 2 ⋅ max ( x , y ) x \oplus y < 2 \cdot \max(x, y) x⊕y<2⋅max(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 1≤i≤n 的 a i ∈ S a_i \in S ai∈S 和 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 1≤i<j≤n 对中都满足,或者指出不存在这样的数组。
如果 a≠b,并且在 a 和 b 不同的第一个位置上,数组 a 的元素比 b 中的相应元素大,那么数组 a 在词法上比相同长度的数组 b 大。
输入
第一行包含一个整数
t
t
t (
1
≤
t
≤
1
0
4
1 \leq t \leq 10^4
1≤t≤104) - 测试用例数。
每个测试用例的第一行包含两个整数 n n n 和 m m m ( 1 ≤ m ≤ n ≤ 1 0 5 1 \leq m \leq n \leq 10^5 1≤m≤n≤105)。
第二行包含 m m m 个唯一整数,按递增顺序排列,代表集合 S S S 的元素 ( 1 ≤ x ≤ n 1 \leq x \leq n 1≤x≤n 对于每个 x ∈ S x \in S x∈S)。
保证所有测试用例中 n n n 的总和不超过 3 ⋅ 1 0 5 3 \cdot 10^5 3⋅105。
输出
对于每个测试用例,如果没有解决方案,则打印
−
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} sm−1 。
推广可得:对于任意位置 i i i,设其可填最大值 a i = s k a_i=s_k ai=sk,KaTeX 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
1≤t≤104) - 测试用例数。
每个测试用例的第一行,也是唯一一行,包含一个整数 n n n ( 2 ≤ n ≤ 1 0 6 2 \leq n \leq 10^6 2≤n≤106)。
保证所有测试用例中 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]=(i⋅∑j>idp[j])+1,这里的 1 1 1 是因为我们可以通过在末尾插入 n − i n - i n−i个 k k k 。
现在我们只需处理初始数组转变为好数组的情况数量。
显然可以构造出 n − 1 n - 1 n−1 种逆序对数量小于等于 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 j−1 种方式。
因此,得到长度为
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=2∑m−1(j−1)=2(m−2)⋅(m−1)−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] n−1+m=3∑n(2(m−2)⋅(m−1)−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:竜崎いち