题目大意
这是魔法,不是戏法!(It’s Magic, Not a Trick!)
时间限制:C/C++/Rust/Pascal 2 秒,其他语言 4 秒
空间限制:C/C++/Rust/Pascal 1024 MB,其他语言 2048 MB
“呃……真麻烦,不过真正的魔法师是不会放弃的。”
自称"超高校级的魔法师"的梦野秘密子在自己面前摆了一排共 n n n 个附魔护符。第 i i i 个护符最初蕴含 a i a_i a i 单位魔力,且每个 a i a_i a i 都是正整数。最近她研读了一本积满灰尘的古老魔导书,破译出了一个以极为特殊的方式操纵魔力的咒语。
每施放一次咒语,她必须严格按顺序执行以下两步:
注魔 :选择任意一个护符,向其中注入恰好 1 1 1 单位自身的魔力,使该护符的魔力增加 1 1 1 。
释放 :选择任意一个在注魔完成之后魔力至少为 x x x 的护符,爆发出耀眼的光芒,从该护符中消耗恰好 x x x 单位魔力,使其魔力减少 x x x 。两步可以选择同一个护符,也可以选择不同的护符,咒语在这一点上是灵活的。
但有一条关键限制:如果注魔完成之后不存在魔力至少为 x x x 的护符,则释放无法进行。此时整个咒语直接失效,什么都不会发生,她试图注魔的那个护符的魔力也保持不变。
只要每一次尝试都能成功、且所有护符的魔力始终保持非负,秘密子就可以任意多次地施放这个咒语。她好奇自己法术的极限:通过选择每次注魔与释放的位置,所有护符剩余魔力之和最小可能是多少?
比起自己算术,她更想去睡一觉,于是她向你——她可靠的助手——求助。由于答案可能很大,你只需要输出答案对 998244353 998244353 9 9 8 2 4 4 3 5 3 取模的结果。
每个测试点包含多组测试数据。
第一行包含一个整数 t t t (1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1 ≤ t ≤ 1 0 4 ),表示测试数据的组数。接下来是各组测试数据的描述。
每组测试数据的第一行包含两个整数 n n n 和 x x x (1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1 ≤ n ≤ 2 ⋅ 1 0 5 ,1 ≤ x ≤ 1 0 9 1 \le x \le 10^9 1 ≤ x ≤ 1 0 9 )。
第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a 1 , a 2 , … , a n (1 ≤ a i ≤ 1 0 18 1 \le a_i \le 10^{18} 1 ≤ a i ≤ 1 0 1 8 )。
保证所有测试数据中 n n n 的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2 ⋅ 1 0 5 。
对于每组测试数据,输出一个整数——所有护符剩余魔力之和的最小可能值对 998244353 998244353 9 9 8 2 4 4 3 5 3 取模的结果。
1 2 3 4 5 6 7 3 3 3 1 1 1 1 4 3 4 10 30 8 7 6
第一组数据 :x = 3 x = 3 x = 3 ,所有护符魔力均为 1 1 1 。无论向哪个护符注魔,注魔后魔力最大也只有 2 < 3 2 < 3 2 < 3 ,无法进行释放,因此秘密子一次咒语也无法施放,剩余魔力之和为 1 + 1 + 1 = 3 1 + 1 + 1 = 3 1 + 1 + 1 = 3 。
第二组数据 :只有一个护符,魔力为 3 3 3 ,x = 4 x = 4 x = 4 。对该护符注魔得到 4 4 4 ,再对它自身释放,魔力变为 0 0 0 。此后无法继续施放,答案为 0 0 0 。
第三组数据 :x = 10 x = 10 x = 1 0 ,初始魔力为 [ 30 , 8 , 7 , 6 ] [30, 8, 7, 6] [ 3 0 , 8 , 7 , 6 ] 。可以按如下方式施放 5 5 5 次咒语:
次数
注魔对象
释放对象
操作后的魔力序列
1
第 2 2 2 个(8 → 9 8 \to 9 8 → 9 )
第 1 1 1 个(30 → 20 30 \to 20 3 0 → 2 0 )
[ 20 , 9 , 7 , 6 ] [20, 9, 7, 6] [ 2 0 , 9 , 7 , 6 ]
2
第 2 2 2 个(9 → 10 9 \to 10 9 → 1 0 )
第 1 1 1 个(20 → 10 20 \to 10 2 0 → 1 0 )
[ 10 , 10 , 7 , 6 ] [10, 10, 7, 6] [ 1 0 , 1 0 , 7 , 6 ]
3
第 3 3 3 个(7 → 8 7 \to 8 7 → 8 )
第 1 1 1 个(10 → 0 10 \to 0 1 0 → 0 )
[ 0 , 10 , 8 , 6 ] [0, 10, 8, 6] [ 0 , 1 0 , 8 , 6 ]
4
第 3 3 3 个(8 → 9 8 \to 9 8 → 9 )
第 2 2 2 个(10 → 0 10 \to 0 1 0 → 0 )
[ 0 , 0 , 9 , 6 ] [0, 0, 9, 6] [ 0 , 0 , 9 , 6 ]
5
第 3 3 3 个(9 → 10 9 \to 10 9 → 1 0 )
第 3 3 3 个(10 → 0 10 \to 0 1 0 → 0 )
[ 0 , 0 , 0 , 6 ] [0, 0, 0, 6] [ 0 , 0 , 0 , 6 ]
此时剩余魔力之和为 6 6 6 ,且无法再继续施放咒语,因此答案为 6 6 6 。
思路讲解
初始放电次数:
1 2 3 4 5 6 7 8 9 10 i128 cnt = 0 ; for (int i = 0 ; i < n; i++){ cnt += a[i] / x; a[i] %= x; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 for (int i = 0 ; i < n; i++){ i128 cost = x - a[i] - 1 ; if (cost <= cnt) { cnt -= cost; a[i] = 0 ; round++; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 sort (all (a), greater<>()); if (a[0 ] == 0 ) { if (cnt >= x - 1 ) { i128 d = cnt / (x - 1 ); cnt -= (x - 1 ) * d; round += d; } }
1 2 3 4 cout << (sum - (x - 1 ) % MOD * round % MOD + MOD) % MOD << "\n" ;
AC代码
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=84457244
源代码(队友的 AC 提交)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 #ifdef LOCAL #define _GLIBCXX_DEBUG #endif #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std;using namespace __gnu_pbds;using ordered_set = tree<int , null_type, less<>, rb_tree_tag, tree_order_statistics_node_update>;using ll = long long ;using ld = long double ;using ull = unsigned long long ;using i128 = __int128_t ;constexpr const ll INF = 1e18 , MOD = 998244353 ;constexpr const ld EPS = 1e-7 ;#define all(x) x.begin(), x.end() #define debug1d(a) \ cerr << #a << " = [" ; \ for (int i = 0; i < (int)(a).size(); i++) \ cerr << (i ? ", " : "" ) << (a)[i]; \ cerr << "]\n" ; #define debug2d(a) \ cerr << #a << " = [\n" ; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " [" ; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ cerr << (j ? ", " : "" ) << a[i][j]; \ cerr << "]\n" ; \ } \ cerr << "]\n" ; #define debug(x) cerr << "[" << #x << "] = " << (x) << "\n" static int last_res;ostream &operator <<(ostream &os, __int128_t x) { if (x < 0 ) os << '-' , x = -x; if (x > 9 ) os << x / 10 ; return os << (char )('0' + x % 10 ); } istream &operator >>(istream &is, __int128_t &x) { string s; if (!(is >> s)) return is; x = 0 ; size_t i = 0 ; bool neg = false ; if (s[0 ] == '-' ) { neg = true ; i = 1 ; } else if (s[0 ] == '+' ) { i = 1 ; } for (; i < s.size (); i++) x = x * 10 + (s[i] - '0' ); if (neg) x = -x; return is; } void solve () { ll n, x; cin >> n >> x; vector<i128> a (n) ; for (int i = 0 ; i < n; i++) cin >> a[i]; i128 cnt = 0 ; i128 sum = 0 ; for (int i = 0 ; i < n; i++) { sum = (sum + a[i]) % MOD; } if (x == 1 ) { cout << sum << "\n" ; return ; } for (int i = 0 ; i < n; i++) { cnt += a[i] / x; a[i] %= x; } i128 round = cnt; sort (all (a), greater<>()); for (int i = 0 ; i < n; i++) { i128 cost = x - a[i] - 1 ; if (cost <= cnt) { cnt -= cost; a[i] = 0 ; round++; } } sort (all (a), greater<>()); if (a[0 ] == 0 ) { if (cnt >= x - 1 ) { i128 d = cnt /(x - 1 ); cnt -= (x - 1 ) * d; round += d; } } cout << (sum - (x - 1 ) % MOD * round % MOD + MOD) % MOD << "\n" ; } int main () { cin.tie (0 )->sync_with_stdio (0 ); int t = 1 ; cin >> t; while (t--) { solve (); } return 0 ; }
AI 注释队友代码版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 #ifdef LOCAL #define _GLIBCXX_DEBUG #endif #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std;using namespace __gnu_pbds;using ordered_set = tree<int , null_type, less<>, rb_tree_tag, tree_order_statistics_node_update>;using ll = long long ;using ld = long double ;using ull = unsigned long long ;using i128 = __int128_t ;constexpr const ll INF = 1e18 , MOD = 998244353 ;constexpr const ld EPS = 1e-7 ;#define all(x) x.begin(), x.end() #define debug1d(a) \ cerr << #a << " = [" ; \ for (int i = 0; i < (int)(a).size(); i++) \ cerr << (i ? ", " : "" ) << (a)[i]; \ cerr << "]\n" ; #define debug2d(a) \ cerr << #a << " = [\n" ; \ for (int i = 0; i < (int)(a).size(); i++) \ { \ cerr << " [" ; \ for (int j = 0; j < (int)(a[i]).size(); j++) \ cerr << (j ? ", " : "" ) << a[i][j]; \ cerr << "]\n" ; \ } \ cerr << "]\n" ; #define debug(x) cerr << "[" << #x << "] = " << (x) << "\n" static int last_res;ostream &operator <<(ostream &os, __int128_t x) { if (x < 0 ) os << '-' , x = -x; if (x > 9 ) os << x / 10 ; return os << (char )('0' + x % 10 ); } istream &operator >>(istream &is, __int128_t &x) { string s; if (!(is >> s)) return is; x = 0 ; size_t i = 0 ; bool neg = false ; if (s[0 ] == '-' ) { neg = true ; i = 1 ; } else if (s[0 ] == '+' ) { i = 1 ; } for (; i < s.size (); i++) x = x * 10 + (s[i] - '0' ); if (neg) x = -x; return is; } void solve () { ll n, x; cin >> n >> x; vector<i128> a (n) ; for (int i = 0 ; i < n; i++) cin >> a[i]; i128 sum = 0 ; for (int i = 0 ; i < n; i++) { sum = (sum + a[i]) % MOD; } if (x == 1 ) { cout << sum << "\n" ; return ; } i128 cnt = 0 ; for (int i = 0 ; i < n; i++) { cnt += a[i] / x; a[i] %= x; } i128 round = cnt; sort (all (a), greater<>()); for (int i = 0 ; i < n; i++) { i128 cost = x - a[i] - 1 ; if (cost <= cnt) { cnt -= cost; a[i] = 0 ; round++; } } sort (all (a), greater<>()); if (a[0 ] == 0 ) { if (cnt >= x - 1 ) { i128 d = cnt / (x - 1 ); cnt -= (x - 1 ) * d; round += d; } } cout << (sum - (x - 1 ) % MOD * round % MOD + MOD) % MOD << "\n" ; } int main () { cin.tie (0 )->sync_with_stdio (0 ); int t = 1 ; cin >> t; while (t--) { solve (); } return 0 ; }
心路历程(WA,TLE,MLE……)