結果
問題 | No.754 畳み込みの和 |
ユーザー | ate |
提出日時 | 2020-09-15 14:23:59 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 308 ms / 5,000 ms |
コード長 | 7,040 bytes |
コンパイル時間 | 1,247 ms |
コンパイル使用メモリ | 99,308 KB |
実行使用メモリ | 15,108 KB |
最終ジャッジ日時 | 2024-06-22 01:43:04 |
合計ジャッジ時間 | 2,903 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 304 ms
14,980 KB |
testcase_01 | AC | 304 ms
14,912 KB |
testcase_02 | AC | 308 ms
15,108 KB |
ソースコード
#include<iostream> #include<vector> #include<cassert> #include<tuple> namespace ate{ template<int64_t p> struct F_p{ using value_type = int64_t; static constexpr inline value_type get_mod(){return p;} value_type value; constexpr F_p():value(value_type{}){} template<class T>constexpr F_p(T v):value(static_cast<value_type>(v<0?v%p+p:v%p)){} template<class T>constexpr operator T()const{return (T)value;} // operator +, -, *, /, ^ constexpr F_p operator + (const F_p& other)const{ return F_p(*this) += other; } constexpr F_p operator - (const F_p& other)const{ return F_p(*this) -= other; } constexpr F_p operator * (const F_p& other)const{ return F_p(*this) *= other; } constexpr F_p operator / (const F_p& other)const{ return F_p(*this) /= other; } template<class T> constexpr F_p operator ^ (const T other)const{ return F_p(*this) ^= other; } constexpr F_p &operator += (const F_p& other){ value+=other.value; if(value>p)value-=p; return *this; } constexpr F_p &operator -= (const F_p& other){ value-=other.value; if(value<0)value+=p; return *this; } constexpr F_p &operator *= (const F_p& other){ value*=other.value; if(value>p)value%=p; return *this; } constexpr F_p &operator /= (const F_p& other){ value*=other.inverse(); if(value>p)value%=p; return *this; } template<class T> constexpr F_p &operator ^= (const T n){ value = mpow(n).value; return *this; } // ext_gcd,inverse,mpow static constexpr value_type ext_gcd(value_type a,value_type b,value_type& x,value_type& y){ if(b==0){x=1,y=0;return a;} value_type d=ext_gcd(b,a%b,y,x); y-=a/b*x;return d; } constexpr value_type inverse()const{ value_type x,y; ext_gcd(value,p,x,y); return x<0?x%p+p:x%p; } template<class T> static constexpr value_type inverse(T val){ value_type x,y; ext_gcd(val,p,x,y); return x<0?x%p+p:x%p; } template<class T> constexpr F_p mpow(T n)const{ F_p res(1),vn(*this); while(n){ if(n&1)res*=vn; vn*=vn; n>>=1; } return res; } template<class T,class U> static constexpr T mpow(T a,U b){ F_p x(a); return static_cast<T>(x.mpow(b).value); } // operator iostream constexpr friend std::istream &operator >> (std::istream& is,F_p& fp){ is>>fp.value; return is; }constexpr friend std::ostream &operator << (std::ostream& os,const F_p& fp){ os<<fp.value; return os; } }; template<int64_t MOD,int primitive_root> struct number_theoretic_transform{ using value_type = F_p<MOD>; using vector_t = std::vector<value_type>; template<class T> static constexpr value_type pow(value_type v,T t){return v^t;} static constexpr int64_t get_mod(){return MOD;} number_theoretic_transform() = default; static void ntt(vector_t& a,bool inv=false){ const int n = std::size(a); for(int i=0,j=1;j+1<n;++j){ for(int k=n>>1;k>(i^=k);k>>=1); if(i<j)std::swap(a[i],a[j]); } for(int t=2;t<=n;t<<=1){ value_type bw = pow(primitive_root,(MOD-1)/t); if(inv)bw = bw.inverse(); for(int i=0;i<n;i+=t){ value_type w = 1; for(int j=0;j<t/2;++j){ const value_type x = a[i+j]; const value_type y = a[i+j+t/2]*w; a[i+j] = x+y; a[i+j+t/2] = x-y; w *= bw; } } } if(inv)for(auto& ai:a)ai/=n; } template<class T> static vector_t convolution(std::vector<T> const& a,std::vector<T> const& b){ const int sz_a = std::size(a); const int sz_b = std::size(b); const int m = sz_a+sz_b-1; int n = 1; while(n<m)n<<=1; vector_t ntt_a(n),ntt_b(n),ntt_c(n); for(int i=0;i<sz_a;++i)ntt_a[i]=static_cast<value_type>(a[i]); for(int i=0;i<sz_b;++i)ntt_b[i]=static_cast<value_type>(b[i]); ntt(ntt_a); ntt(ntt_b); for(int i=0;i<n;++i)ntt_c[i]=ntt_a[i]*ntt_b[i]; bool inverse = true; ntt(ntt_c,inverse); ntt_c.resize(m); return ntt_c; } }; struct NTT{ using NTT_1 = number_theoretic_transform<998244353,3>; using NTT_2 = number_theoretic_transform<754974721,11>; using NTT_3 = number_theoretic_transform<469762049,3>; using NTT_4 = number_theoretic_transform<167772161,3>; using NTT_5 = number_theoretic_transform<1224736769,3>; using NTT_6 = number_theoretic_transform<1012924417,5>; NTT(){} static std::tuple<int64_t,int64_t,int64_t> ext_gcd(int64_t a,int64_t b){ if(b==0)return {a,1,0};auto[d,y,x]=ext_gcd(b,a%b);return {d,x,y-(a/b*x)}; } static constexpr inline int64_t safe_mod(int64_t a,int64_t m){a%=m;return(a<0?a+m:a);} static int64_t mod_inv(int64_t a,int64_t m){ auto[d,x,y]=ext_gcd(a,m);return(d!=1?-1:safe_mod(x,m)); } static int64_t gerner (std::vector<int64_t> b,std::vector<int64_t> m,const int64_t MOD){ const int n = std::size(b); m.emplace_back(MOD); std::vector<int64_t> coeffs(std::size(m),1); std::vector<int64_t> constants(std::size(m),0); for(int k=0;k<n;++k){ const int64_t m_inv = mod_inv(coeffs[k],m[k]); const int64_t t = safe_mod((b[k]-constants[k])*m_inv,m[k]); for(int i=k+1;i<std::size(m);++i){ (constants[i] += t*coeffs[i]) %= m[i]; (coeffs[i] *= m[k]) %= m[i]; } } return constants.back(); } template<class T> static std::vector<int64_t> convolution(std::vector<T>const& a,std::vector<T>const& b,const int64_t MOD){ const auto ntt1 = NTT_1::convolution(a,b); const auto ntt2 = NTT_2::convolution(a,b); const auto ntt3 = NTT_3::convolution(a,b); const int n = std::size(a)+std::size(b)-1; const int m = 3; const std::vector<int64_t> mods = {NTT_1::get_mod(),NTT_2::get_mod(),NTT_3::get_mod()}; std::vector<int64_t> conv(n); for(int i=0;i<n;++i){ const std::vector<int64_t> b = {ntt1[i],ntt2[i],ntt3[i]}; conv[i] = gerner(b,mods,MOD); } return conv; } }; } //namespace ate int main(){ using namespace std; std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); constexpr char newl = '\n'; int n; cin>>n; vector<int64_t> a(n+1),b(n+1); for(auto& ai:a)cin>>ai; for(auto& bi:b)cin>>bi; auto c = ate::NTT::convolution(a,b,1e9+7); ate::F_p<(int)1e9+7> ans = 0; for(int i=0;i<=n and i<size(c);++i)ans+=c[i]; cout<<(ans)<<endl; } void solve_fft(){ using namespace std; std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); constexpr char newl = '\n'; int n; cin>>n; vector<int64_t> a(n),b(n); for(int i=0;i<n;++i)cin>>a[i]>>b[i]; auto c = ate::NTT::NTT_1::convolution(a,b); cout<<0<<newl; for(auto ci:c)cout<<ci<<newl; }