【多项式基础操作:分治相乘】

原因

在进行一串多项式相乘的操作时,时间复杂度将会爆掉
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(nmlog(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 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值