原因
在进行一串多项式相乘的操作时,时间复杂度将会爆掉
f f t / n t t fft/ntt fft/ntt的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)
粗略计算一下,大脑过载问的gpt,gpt说是 O ( n ∗ m ∗ l o g ( n + m ) ) O(n*m*log(n+m)) O(n∗m∗log(n+m))
经验告诉我们1e5个长度小于10的多项式相乘也会爆,
于是有人说:长度很小?多项式快速幂启动!
你ac了本题(),大概能把一个 n n n干成 l o g n logn logn
但是没有更好的题目,只有更糟糕的数据,Time limit exceeded on test 53
这时我们需要用到一个在多项式题目中常用的小技巧,分治
代码:
auto build = [ & ] ( auto&& build , i64 l , i64 r ) -> Poly <> {
if ( r - l == 1 ) {
return Poly <>( vector <Z> ( v [ l ] + 1 , 1 ) ) ;
} else {
i64 mid = ( l + r ) / 2 ;
return build ( build , l , mid ) * build ( build , mid , r ) ;
}
};
这是一个常相见的类线段树代码
这样你就能以 O ( n l o g 2 ( n ) ) O(nlog^2(n)) O(nlog2(n)) ac这道题Time limit exceeded on test 53
ac代码
void solve () {
i64 n ; cin >> n ;
vector <i64> v ( n ) ;
for ( int i = 0 ; i < n ; ++ i ) cin >> v [ i ] ;
std::map <i64, i64> map ;
for ( auto u : v ) ++ map [ u ] ;
i64 cnt1 = 0 , cnt2 = 0 ;
i64 max = 0 ; i64 len = 0 ;
v.clear () ;
for ( auto [ _ , x ] : map ) {
v.push_back ( x ) ;
}
auto build = [ & ] ( auto&& build , i64 l , i64 r ) -> Poly <> {
if ( r - l == 1 ) {
return Poly <>( vector <Z> ( v [ l ] + 1 , 1 ) ) ;
} else {
i64 mid = ( l + r ) / 2 ;
return build ( build , l , mid ) * build ( build , mid , r ) ;
}
};
Poly a = build ( build , 0 , v.size () ) ;
cout << a [ a.size () / 2 ] << endl ;
}
完整代码
// #pragma GCC optimize("Ofast")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
// #pragma GCC optimize("unroll-loops")
# include <bits/stdc++.h>
# ifdef LOCAL
# include "C:\Users\Kevin\Desktop\demo\C++_code\debug.h"
#endif
using namespace std ;
namespace predefine {
const long long inf = 0x3f3f3f3f3f3f3f3f ;
using ll = long long ;using i64 = long long ;using Long = long long ;
using Int = __int128 ;using pll = pair < Long , Long > ;
# define af( i , a , b ) for ( Long i = a ; i <= b ; ++ i )
# define df( i , a , b ) for ( Long i = a ; i >= b ; -- i )
# define lowbit( x ) ( x & ( - x ) )
}
using namespace predefine ;
//----- 板子 ---------------------------------------------------------------------------------------------------------
using i64 = long long;
template<class T>
constexpr T power(T a, i64 b) {
T res = 1 ;
for (; b; b /= 2, a *= a) {
if (b % 2) {
res *= a;
}
}
return res;
}
template<int P>
struct MInt {
int x;
constexpr MInt() : x{
} {
}
constexpr MInt(i64 x) : x{
norm(x % getMod())} {
}
static int Mod;
constexpr static int getMod() {
if (P > 0) {
return P;
} else {
return Mod;
}
}
constexpr static void setMod(int Mod_) {
Mod = Mod_;
}
constexpr int norm(int x) const {
if (x < 0) {
x += getMod();
}
if (x >= getMod()) {
x -= getMod();
}
return x;
}
constexpr int val() const {
return x;
}
explicit constexpr operator int() const {
return x;
}
constexpr MInt operator-() const {
MInt res;
res.x = norm(getMod() - x);
return res;
}
constexpr MInt inv() const {
assert(x != 0);
return power(*this, getMod() - 2);
}
constexpr MInt &operator*=(MInt rhs) & {
x = 1LL * x * rhs.x % getMod();
return *this;
}
constexpr MInt &operator+=(MInt rhs) & {
x = norm(x + rhs.x);
return *this;
}
constexpr MInt &operator-=(MInt rhs) & {
x = norm(x - rhs.x);
return *this;
}
constexpr MInt &operator/=(MInt rhs) & {
return *this *= rhs.inv();
}
friend constexpr MInt operator*(MInt lhs, MInt rhs) {
MInt res = lhs;
res *= rhs;
return res;
}
friend constexpr MInt operator+(MInt lhs, MInt rhs) {
MInt res = lhs;
res += rhs;
return res;
}
friend constexpr MInt operator-(MInt lhs, MInt rhs) {
MInt res = lhs;
res -= rhs;
return res;
}
friend constexpr MInt operator/(MInt lhs, MInt rhs) {
MInt res = lhs;
res /= rhs;
return res;
}
friend