题目大意:
有 N ( ≤ 1 e 18 ) N(\le 1e18) N(≤1e18)个空集合(集合内元素不可重复),被依次标记为 1 ∼ N 1 \sim N 1∼N,会执行 N N N次操作,第 i i i次操作,从 1 ∼ M ( ≤ 1 e 18 ) 1\sim M(\le 1e18) 1∼M(≤1e18)中选择一个数 x x x,在 i ∼ N i\sim N i∼N的集合中加入元素 x x x。执行完 N N N次操作之后,有多少可能不同的结果,答案对 998244353 998244353 998244353取模
- m i n ( N , M ) ≤ 1 e 6 min(N, M) \le 1e6 min(N,M)≤1e6
解题思路:(思路来源:lkaiii)
- 首先第一种操作有 M M M种填法,而之后的 2 ∼ N 2\sim N 2∼N,倘若再填第一种操作的数,就相当于没填
- 设还要放 k k k种数,那么就相当于从 n − 1 n-1 n−1个箱子中选出 k k k个来放这 k k k种数,即 C n − 1 k C_{n-1}^k Cn−1k,而这 k k k种数要从 m − 1 m-1 m−1中取且其有顺序,即 A m − 1 k A_{m-1}^k Am−1k种,所以答案是: m ∑ k = 0 m i n ( n − 1 , m − 1 ) C n − 1 k A m − 1 k m\sum_{k=0}^{min(n-1,m-1)}C_{n-1}^kA_{m-1}^k m∑k=0min(n−1,m−1)Cn−1kAm−1k
- 对于剩下的 n − 1 − k n-1-k n−1−k个操作,可以都填第一种操作数,所以就相当于是没填了,只管这 k k k个就行
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 998244353;
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int t, cas = 0;
ll n, m;
int main() {
IOS;
cin >> t;
while (t--) {
cin >> n >> m;
ll c = 1, a = 1, ans = 0, rc = n - 1, ra = m - 1;
for (ll k = 0; k <= min(n - 1, m - 1); k++) {
ans = (ans + m % mod * c % mod * a % mod) % mod;
c = c * qpow(k + 1, mod - 2) % mod * (rc % mod) % mod;
rc--;
a = a * (ra % mod) % mod;
ra--;
}
cout << "Case #" << ++cas << ": " << ans << endl;
}
return 0;
}
反思:
- 不愿意动手在纸上画一画,太懒了,这显然不行
- 还有对于题目条件的理解错误,看见 ≤ 1 e 6 \le 1e6 ≤1e6就想着分类讨论了,不往其他方面想