namespace Comb { // 组合数加逆元,依赖于这个MAXN(初始化) vector<ll> frac, infrac; int ln = 1; bool initialized = false; // 在 k=0或者更小的时候 return 1 inline ll binpow(ll a, ll k){ ll res = 1; a %= mod; while (k > 0) { if (k & 1) res = (res * a) % mod; a = (a * a) % mod; k >>= 1; } return res; }
voidComb(int n){ ln = n; frac.assign(n + 5, 1); infrac.assign(n + 5, 1); for (int i = 1; i <= ln; ++i) { frac[i] = (frac[i - 1] * i) % mod; } infrac[ln] = binpow(frac[ln], mod - 2); for (int i = ln - 1; i >= 0; --i) { infrac[i] = (infrac[i + 1] * (i + 1)) % mod; } }
inline ll CC(ll n, ll k){ if (k < 0 || k > n) { #ifdef LOCAL cerr << "CC 组合数传入参数不合法,可能是传入顺序错了\n"; #endif return0; // Return 0 if k is out of range [0, n] } if (!initialized) { Comb(MAXN); initialized = true; } ll res = frac[n]; res = (res * infrac[n - k]) % mod; res = (res * infrac[k]) % mod; return res; }
inline ll PP(ll n, ll k){ if (k < 0 || k > n) { #ifdef LOCAL cerr << "PP 排列数传入参数不合法,可能是传入顺序错了\n"; #endif return0; } if (!initialized) { Comb(MAXN); initialized = true; } ll res = frac[n] * infrac[n - k]; res %= mod; return res; } } // namespace Comb usingnamespace Comb;
voidSolve(){ ll N, M; cin >> N >> M; // i 花色,多取 j 张,内部的数量是多少?(当然,这个多取 j 张,是 A 多取,还是 B 多取,也就是我们一念之间的事情) vector<ll> dp1(M / 2 + 2); for (int j = 0; j <= M / 2; ++j) { dp1[j] = CC(M, M / 2 + j) - CC(M, M / 2 + j + 1); dp1[j] %= mod; } // 在第一个花色多余 j 张的情况下(一开始多取的 ≥ j),处理到 i 花色的时候 // 总共有的这个情况数量 vector<ll> dp2 = dp1; vector<ll> ndp; for (int i = 2; i <= N; ++i) { ndp.assign(M / 2 + 2, 0); for (int j = 0; j <= M / 2; ++j) { for (int k = j; k <= M / 2; ++k) { ndp[j] += dp2[k] * dp1[k - j]; ndp[j] %= mod; } } swap(dp2, ndp); } // 第一个花色,最后必须是剩余 0 才可以 ll ans = dp2[0]; ans %= mod; if (ans < 0) ans += mod; cout << ans << "\n"; }
signedmain(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); #ifdef LOCAL cout.setf(ios::unitbuf); // 无缓冲流,方便我们调试 #endif
#include<bits/stdc++.h> #define all(vec) vec.begin(), vec.end() #define PB push_back #define PF push_front #define EB emplace_back #define EF emplace_front #define EM emplace #define FI first #define SE second #define pct __builtin_popcountll #define ctz __builtin_ctzll #define SZ(a) ((long long) a.size()) #define FOR(i, a, b) for (int i = (a); i <= (b); ++i) #define ROF(i, a, b) for (int i = (a); i >= (b); --i) #define debug(var) cerr << #var << ":" << var << "\n"; #define cend cerr << "\n-----------\n" #define fsp(x) fixed << setprecision(x)
usingnamespace std;
using ll = longlong; using ull = unsignedlonglong; using DB = double; using LD = longdouble; using CD = complex<double>; staticconstexpr ll MAXN = (ll) 1e6 + 10, INF = (1ll << 61) - 1; staticconstexpr ll mod = (ll) 1e9 + 7; staticconstexprdouble eps = 1e-8; constdouble pi = acos(-1.0);
ll lT;
structU { using u128 = __uint128_t; staticconstexpr ll MOD = (1ULL << 61) - 1;
ll v;
U() : v(0) { }
U(ll x) { ll t = x % MOD; if (t < 0) t += MOD; v = (ll) t; }
staticinline ll add(ll a, ll b){ ll s = a + b; if (s >= MOD) s -= MOD; return s; }
staticinline ll sub(ll a, ll b){ return (a >= b) ? (a - b) : (a + MOD - b); }
staticinline ll mul(ll a, ll b){ u128 t = (u128) a * b; ll s = ll(t & MOD) + ll(t >> 61); if (s >= MOD) s -= MOD; return s; }
U &operator+=(const U &o) { v = add(v, o.v); return *this; }
U &operator-=(const U &o) { v = sub(v, o.v); return *this; }
U &operator*=(const U &o) { v = mul(v, o.v); return *this; }
friend U operator+(U a, const U &b) { a += b; return a; }
friend U operator-(U a, const U &b) { a -= b; return a; }
friend U operator*(U a, const U &b) { a *= b; return a; }
friendbooloperator==(const U &a, const U &b) { return a.v == b.v; } friendbooloperator!=(const U &a, const U &b) { return a.v != b.v; } friendbooloperator<(const U &a, const U &b) { return a.v < b.v; } friendbooloperator>(const U &a, const U &b) { return a.v > b.v; } friendbooloperator<=(const U &a, const U &b) { return a.v <= b.v; } friendbooloperator>=(const U &a, const U &b) { return a.v >= b.v; } };
const U base = 131;
// AC https://vjudge.net/solution/65151535 string matching 测试了find函数功能 // 2025/11/4 // AC https://www.luogu.com.cn/record/245201000 测试了这个push,pop,以及增强get鲁棒性。 // 2026/3/21 改为了 0-based structHS { vector<U> hs, powBase; U hashval; ll n; string s;
HS(const string &ls) { n = SZ(ls); s = ls; hs.assign(n, 0); powBase.assign(n + 1, 0); powBase[0] = 1; for (ll i = 1; i <= n; ++i) { powBase[i] = powBase[i - 1] * base; } if (n > 0) { hs[0] = U(s[0]); for (ll i = 1; i < n; ++i) { hs[i] = hs[i - 1] * base + U(s[i]); } hashval = hs[n - 1]; } else { hashval = 0; } }
U get(ll l, ll r){ if (n == 0) return0; l = max(0ll, l); r = min(n - 1, r); if (l > r) return0; if (l == 0) return hs[r]; return hs[r] - hs[l - 1] * powBase[r - l + 1]; }
U get(ll l){ returnget(l, n - 1); }
ll find(const string &ls){ U hxfind = 0; ll m = SZ(ls); if (m == 0) return n + 1; if (m > n) return0; for (ll i = 0; i < m; ++i) { hxfind = hxfind * base + ls[i]; } ll res = 0; for (ll r = m - 1; r < n; ++r) { U hx = get(r - m + 1, r); if (hx == hxfind) { res++; } } return res; }