結果
| 問題 |
No.931 Multiplicative Convolution
|
| コンテスト | |
| ユーザー |
LayCurse
|
| 提出日時 | 2019-11-22 22:14:55 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 112 ms / 2,000 ms |
| コード長 | 16,397 bytes |
| コンパイル時間 | 4,108 ms |
| コンパイル使用メモリ | 229,300 KB |
| 最終ジャッジ日時 | 2025-01-08 05:05:54 |
|
ジャッジサーバーID (参考情報) |
judge2 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 14 |
ソースコード
#pragma GCC optimize ("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MD (998244353U)
#define MINT_W (32U)
#define MINT_R (301989884U)
#define MINT_RR (932051910U)
#define MINT_MDNINV (998244351U)
#define MD_PRIMITIVE_ROOT (3U)
#define PI 3.14159265358979323846
void *wmem;
char memarr[96000000];
template<class S, class T> inline S max_L(S a,T b){
return a>=b?a:b;
}
template<class T> inline void walloc1d(T **arr, int x, void **mem = &wmem){
static int skip[16] = {0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
(*mem) = (void*)( ((char*)(*mem)) + skip[((unsigned long long)(*mem)) & 15] );
(*arr)=(T*)(*mem);
(*mem)=((*arr)+x);
}
struct Mint{
unsigned val;
Mint(){
val=0;
}
Mint(int a){
val = mulR(a);
}
Mint(unsigned a){
val = mulR(a);
}
Mint(long long a){
val = mulR(a);
}
Mint(unsigned long long a){
val = mulR(a);
}
inline unsigned mulR(unsigned a){
return (unsigned long long)a*MINT_R%MD;
}
inline unsigned mulR(int a){
if(a < 0){
a = a%((int)MD)+(int)MD;
}
return mulR((unsigned)a);
}
inline unsigned mulR(unsigned long long a){
return mulR((unsigned)(a%MD));
}
inline unsigned mulR(long long a){
a %= MD;
if(a < 0){
a += MD;
}
return mulR((unsigned)a);
}
inline unsigned reduce(unsigned T){
unsigned m = T * MINT_MDNINV;
unsigned t = (unsigned)((T + (unsigned long long)m*MD) >> MINT_W);
if(t >= MD){
t -= MD;
}
return t;
}
inline unsigned reduce(unsigned long long T){
unsigned m = (unsigned)T * MINT_MDNINV;
unsigned t = (unsigned)((T + (unsigned long long)m*MD) >> MINT_W);
if(t >= MD){
t -= MD;
}
return t;
}
inline unsigned get(){
return reduce(val);
}
inline Mint &operator+=(Mint a){
val += a.val;
if(val >= MD){
val -= MD;
}
return *this;
}
inline Mint &operator-=(Mint a){
if(val < a.val){
val = val + MD - a.val;
}
else{
val -= a.val;
}
return *this;
}
inline Mint &operator*=(Mint a){
val = reduce((unsigned long long)val*a.val);
return *this;
}
inline Mint &operator/=(Mint a){
return *this *= a.inverse();
}
inline Mint operator+(Mint a){
return Mint(*this)+=a;
}
inline Mint operator-(Mint a){
return Mint(*this)-=a;
}
inline Mint operator*(Mint a){
return Mint(*this)*=a;
}
inline Mint operator/(Mint a){
return Mint(*this)/=a;
}
inline Mint operator+(int a){
return Mint(*this)+=Mint(a);
}
inline Mint operator-(int a){
return Mint(*this)-=Mint(a);
}
inline Mint operator*(int a){
return Mint(*this)*=Mint(a);
}
inline Mint operator/(int a){
return Mint(*this)/=Mint(a);
}
inline Mint operator+(long long a){
return Mint(*this)+=Mint(a);
}
inline Mint operator-(long long a){
return Mint(*this)-=Mint(a);
}
inline Mint operator*(long long a){
return Mint(*this)*=Mint(a);
}
inline Mint operator/(long long a){
return Mint(*this)/=Mint(a);
}
inline Mint operator-(void){
Mint res;
if(val){
res.val=MD-val;
}
else{
res.val=0;
}
return res;
}
inline operator bool(void){
return val!=0;
}
inline operator int(void){
return get();
}
inline operator long long(void){
return get();
}
inline Mint inverse(){
int a = val;
int b = MD;
int u = 1;
int v = 0;
int t;
Mint res;
while(b){
t = a / b;
a -= t * b;
swap(a, b);
u -= t * v;
swap(u, v);
}
if(u < 0){
u += MD;
}
res.val = (unsigned long long)u*MINT_RR % MD;
return res;
}
inline Mint pw(unsigned long long b){
Mint a(*this);
Mint res;
res.val = MINT_R;
while(b){
if(b&1){
res *= a;
}
b >>= 1;
a *= a;
}
return res;
}
inline bool operator==(int a){
return mulR(a)==val;
}
inline bool operator!=(int a){
return mulR(a)!=val;
}
}
;
inline Mint operator+(int a, Mint b){
return Mint(a)+=b;
}
inline Mint operator-(int a, Mint b){
return Mint(a)-=b;
}
inline Mint operator*(int a, Mint b){
return Mint(a)*=b;
}
inline Mint operator/(int a, Mint b){
return Mint(a)/=b;
}
inline Mint operator+(long long a, Mint b){
return Mint(a)+=b;
}
inline Mint operator-(long long a, Mint b){
return Mint(a)-=b;
}
inline Mint operator*(long long a, Mint b){
return Mint(a)*=b;
}
inline Mint operator/(long long a, Mint b){
return Mint(a)/=b;
}
inline void rd(int &x){
int k;
int m=0;
x=0;
for(;;){
k = getchar_unlocked();
if(k=='-'){
m=1;
break;
}
if('0'<=k&&k<='9'){
x=k-'0';
break;
}
}
for(;;){
k = getchar_unlocked();
if(k<'0'||k>'9'){
break;
}
x=x*10+k-'0';
}
if(m){
x=-x;
}
}
inline void wt_L(char a){
putchar_unlocked(a);
}
inline void wt_L(int x){
int s=0;
int m=0;
char f[10];
if(x<0){
m=1;
x=-x;
}
while(x){
f[s++]=x%10;
x/=10;
}
if(!s){
f[s++]=0;
}
if(m){
putchar_unlocked('-');
}
while(s--){
putchar_unlocked(f[s]+'0');
}
}
template<class T> inline int isPrime_L(T n){
T i;
if(n<=1){
return 0;
}
if(n<=3){
return 1;
}
if(n%2==0){
return 0;
}
for(i=3;i*i<=n;i+=2){
if(n%i==0){
return 0;
}
}
return 1;
}
template<class T> int Factor_L(T N, T fac[], int fs[]){
T i;
int sz = 0;
if(N%2==0){
fac[sz] = 2;
fs[sz] = 1;
N /= 2;
while(N%2==0){
N /= 2;
fs[sz]++;
}
sz++;
}
for(i=3;i*i<=N;i+=2){
if(N%i==0){
fac[sz] = i;
fs[sz] = 1;
N /= i;
while(N%i==0){
N /= i;
fs[sz]++;
}
sz++;
}
}
if(N > 1){
fac[sz] = N;
fs[sz] = 1;
sz++;
}
return sz;
}
template<class T> int Divisor_L(T N, T res[], void *mem = wmem){
int i;
int j;
int k;
int s;
int sz = 0;
T *fc;
int *fs;
int fsz;
walloc1d(&fc, 100, &mem);
walloc1d(&fs, 100, &mem);
fsz =Factor_L(N, fc, fs);
res[sz++] = 1;
for(i=(0);i<(fsz);i++){
s = sz;
k = s * fs[i];
for(j=(0);j<(k);j++){
res[sz++] = res[j] * fc[i];
}
}
sort(res, res+sz);
return sz;
}
unsigned long long powmod(unsigned long long a, unsigned long long b, unsigned long long m){
unsigned long long r = 1;
while(b){
if(b&1){
r = r * a % m;
}
b>>=1;
a = a * a % m;
}
return r;
}
long long primitiveRoot(long long p, void *mem = wmem){
int ys;
long long *y;
long long r;
if(!isPrime_L(p)){
return -1;
}
walloc1d(&y, 100000, &mem);
ys =Divisor_L(p-1, y, mem);
for(r=(1);r<(p);r++){
int i;
for(i=(0);i<(ys-1);i++){
if(powmod(r,y[i],p) == 1){
goto OC5CYxKD;
}
}
return r;
OC5CYxKD:;
}
return -1;
}
struct fft_pnt{
double x;
double y;
fft_pnt(void){
}
fft_pnt(double a, double b){
x = a;
y = b;
}
void set(double a, double b){
x = a;
y = b;
}
fft_pnt& operator+=(fft_pnt a){
x+=a.x;
y+=a.y;
return *this;
}
fft_pnt& operator-=(fft_pnt a){
x-=a.x;
y-=a.y;
return *this;
}
fft_pnt& operator*=(fft_pnt a){
fft_pnt p = *this;
x = p.x*a.x-p.y*a.y;
y = p.x*a.y+p.y*a.x;
return *this;
}
fft_pnt operator+(fft_pnt a){
return fft_pnt(*this) += a;
}
fft_pnt operator-(fft_pnt a){
return fft_pnt(*this) -= a;
}
fft_pnt operator*(fft_pnt a){
return fft_pnt(*this) *= a;
}
}
;
void fft_L(int n, fft_pnt x[], void *mem){
int i;
int j;
int n1;
int n2;
int n3;
int step = 1;
double theta = 2*PI / n;
double tmp;
fft_pnt w1;
fft_pnt w2;
fft_pnt w3;
fft_pnt a;
fft_pnt b;
fft_pnt c;
fft_pnt d;
fft_pnt aa;
fft_pnt bb;
fft_pnt cc;
fft_pnt dd;
fft_pnt *y = (fft_pnt*)mem;
while(n > 2){
n1 = n / 4;
n2 = n1 + n1;
n3 = n1 + n2;
for(i=(0);i<(n1);i++){
w1 = fft_pnt(cos(i*theta),-sin(i*theta));
w2 = w1*w1;
w3 = w1*w2;
for(j=(0);j<(step);j++){
a = x[j+step*i];
b = x[j+step*(i+n1)];
c = x[j+step*(i+n2)];
d = x[j+step*(i+n3)];
aa = a + c;
bb = a - c;
cc = b + d;
dd = b - d;
tmp = dd.y;
dd.y = dd.x;
dd.x = -tmp;
y[j+step*(4*i )] = aa + cc;
y[j+step*(4*i+1)] = w1*(bb - dd);
y[j+step*(4*i+2)] = w2*(aa - cc);
y[j+step*(4*i+3)] = w3*(bb + dd);
}
}
n /= 4;
step *= 4;
theta *= 4;
swap(x,y);
}
if(n==2){
for(i=(0);i<(step);i++){
y[i] = x[i] + x[i+step];
y[i+step] = x[i] - x[i+step];
}
n /= 2;
step *= 2;
theta *= 2;
swap(x,y);
}
for(i=(0);i<(step);i++){
y[i] = x[i];
}
}
void fftinv_L(int n, fft_pnt x[], void *mem){
int i;
int j;
int n1;
int n2;
int n3;
int step = 1;
double theta = 2*PI / n;
double tmp;
fft_pnt w1;
fft_pnt w2;
fft_pnt w3;
fft_pnt a;
fft_pnt b;
fft_pnt c;
fft_pnt d;
fft_pnt aa;
fft_pnt bb;
fft_pnt cc;
fft_pnt dd;
fft_pnt *y = (fft_pnt*)mem;
while(n > 2){
n1 = n / 4;
n2 = n1 + n1;
n3 = n1 + n2;
for(i=(0);i<(n1);i++){
w1 = fft_pnt(cos(i*theta),sin(i*theta));
w2 = w1*w1;
w3 = w1*w2;
for(j=(0);j<(step);j++){
a = x[j+step*i];
b = x[j+step*(i+n1)];
c = x[j+step*(i+n2)];
d = x[j+step*(i+n3)];
aa = a + c;
bb = a - c;
cc = b + d;
dd = b - d;
tmp = dd.y;
dd.y = dd.x;
dd.x = -tmp;
y[j+step*(4*i )] = aa + cc;
y[j+step*(4*i+1)] = w1*(bb + dd);
y[j+step*(4*i+2)] = w2*(aa - cc);
y[j+step*(4*i+3)] = w3*(bb - dd);
}
}
n /= 4;
step *= 4;
theta *= 4;
swap(x,y);
}
if(n==2){
for(i=(0);i<(step);i++){
y[i] = x[i] + x[i+step];
y[i+step] = x[i] - x[i+step];
}
n /= 2;
step *= 2;
theta *= 2;
swap(x,y);
}
for(i=(0);i<(step);i++){
y[i] = x[i];
}
}
void convolution_L(double A[], int As, double B[], int Bs, double res[], int Rs, void *mem = wmem){
int i;
int n;
int n2;
double mul;
fft_pnt *a;
fft_pnt *b;
n =max_L(As+Bs, Rs);
for(n2=1;n2<n;n2*=2){
;
}
walloc1d(&a, n2, &mem);
walloc1d(&b, n2, &mem);
for(i=(0);i<(As);i++){
a[i].set(A[i], 0);
}
int aTt_SmvX = n2;
for(i=(As);i<(aTt_SmvX);i++){
a[i].set(0,0);
}
for(i=(0);i<(Bs);i++){
b[i].set(B[i], 0);
}
int bXO5jt5I = n2;
for(i=(Bs);i<(bXO5jt5I);i++){
b[i].set(0,0);
}
fft_L(n2, a, mem);
fft_L(n2, b, mem);
for(i=(0);i<(n2);i++){
a[i] *= b[i];
}
fftinv_L(n2, a, mem);
mul = 1.0 / n2;
for(i=(0);i<(Rs);i++){
res[i] = a[i].x * mul;
}
}
void convolution_L(double A[], int As, double res[], int Rs, void *mem = wmem){
int i;
int n;
int n2;
double mul;
fft_pnt *a;
n =max_L(As+As, Rs);
for(n2=1;n2<n;n2*=2){
;
}
walloc1d(&a, n2, &mem);
for(i=(0);i<(As);i++){
a[i].set(A[i], 0);
}
int vJNsb2nO = n2;
for(i=(As);i<(vJNsb2nO);i++){
a[i].set(0,0);
}
fft_L(n2, a, mem);
for(i=(0);i<(n2);i++){
a[i] *= a[i];
}
fftinv_L(n2, a, mem);
mul = 1.0 / n2;
for(i=(0);i<(Rs);i++){
res[i] = a[i].x * mul;
}
}
void fft_L(int n, Mint x[], Mint root, void *mem){
int i;
int j;
int n1;
int n2;
int n3;
int step = 1;
Mint w1;
Mint w2;
Mint w3;
Mint a;
Mint b;
Mint c;
Mint d;
Mint aa;
Mint bb;
Mint cc;
Mint dd;
Mint tmp;
Mint *y;
walloc1d(&y, n, &mem);
tmp = root.pw((MD-1)/4*3);
root = root.pw((MD-1)/n);
while(n > 2){
n1 = n / 4;
n2 = n1 + n1;
n3 = n1 + n2;
w1.val = MINT_R;
for(i=(0);i<(n1);i++){
w2 = w1*w1;
w3 = w1*w2;
for(j=(0);j<(step);j++){
a = x[j+step*i];
b = x[j+step*(i+n1)];
c = x[j+step*(i+n2)];
d = x[j+step*(i+n3)];
aa = a + c;
bb = a - c;
cc = b + d;
dd = (b - d) * tmp;
y[j+step*(4*i )] = aa + cc;
y[j+step*(4*i+1)] = w1*(bb - dd);
y[j+step*(4*i+2)] = w2*(aa - cc);
y[j+step*(4*i+3)] = w3*(bb + dd);
}
w1 *= root;
}
n /= 4;
step *= 4;
root *= root;
root *= root;
swap(x,y);
}
if(n==2){
for(i=(0);i<(step);i++){
y[i] = x[i] + x[i+step];
y[i+step] = x[i] - x[i+step];
}
n /= 2;
step *= 2;
root *= root;
swap(x,y);
}
for(i=(0);i<(step);i++){
y[i] = x[i];
}
}
void fftinv_L(int n, Mint x[], Mint root, void *mem){
int i;
int j;
int n1;
int n2;
int n3;
int step = 1;
Mint w1;
Mint w2;
Mint w3;
Mint a;
Mint b;
Mint c;
Mint d;
Mint aa;
Mint bb;
Mint cc;
Mint dd;
Mint tmp;
Mint *y;
walloc1d(&y, n, &mem);
root = root.inverse();
tmp = root.pw((MD-1)/4);
root = root.pw((MD-1)/n);
while(n > 2){
n1 = n / 4;
n2 = n1 + n1;
n3 = n1 + n2;
w1.val = MINT_R;
for(i=(0);i<(n1);i++){
w2 = w1*w1;
w3 = w1*w2;
for(j=(0);j<(step);j++){
a = x[j+step*i];
b = x[j+step*(i+n1)];
c = x[j+step*(i+n2)];
d = x[j+step*(i+n3)];
aa = a + c;
bb = a - c;
cc = b + d;
dd = (b - d) * tmp;
y[j+step*(4*i )] = aa + cc;
y[j+step*(4*i+1)] = w1*(bb + dd);
y[j+step*(4*i+2)] = w2*(aa - cc);
y[j+step*(4*i+3)] = w3*(bb - dd);
}
w1 *= root;
}
n /= 4;
step *= 4;
root *= root;
root *= root;
swap(x,y);
}
if(n==2){
for(i=(0);i<(step);i++){
y[i] = x[i] + x[i+step];
y[i+step] = x[i] - x[i+step];
}
n /= 2;
step *= 2;
root *= root;
swap(x,y);
}
for(i=(0);i<(step);i++){
y[i] = x[i];
}
}
void convolution_L(Mint A[], int As, Mint B[], int Bs, Mint res[], int Rs, Mint root = MD_PRIMITIVE_ROOT, void *mem = wmem){
int i;
int n;
int n2;
Mint *a;
Mint *b;
Mint r;
n =max_L(As+Bs, Rs);
for(n2=1;n2<n;n2*=2){
;
}
walloc1d(&a, n2, &mem);
walloc1d(&b, n2, &mem);
for(i=(0);i<(As);i++){
a[i] = A[i];
}
int U5xJbqP4 = n2;
for(i=(As);i<(U5xJbqP4);i++){
a[i].val = 0;
}
for(i=(0);i<(Bs);i++){
b[i] = B[i];
}
int dDIyew82 = n2;
for(i=(Bs);i<(dDIyew82);i++){
b[i].val = 0;
}
fft_L(n2, a, root, mem);
fft_L(n2, b, root, mem);
for(i=(0);i<(n2);i++){
a[i] *= b[i];
}
fftinv_L(n2, a, root, mem);
r = Mint(n2).inverse();
for(i=(0);i<(Rs);i++){
res[i] = a[i] * r;
}
}
void convolution_L(Mint A[], int As, Mint res[], int Rs, Mint root = MD_PRIMITIVE_ROOT, void *mem = wmem){
int i;
int n;
int n2;
Mint *a;
Mint r;
n =max_L(2*As, Rs);
for(n2=1;n2<n;n2*=2){
;
}
walloc1d(&a, n2, &mem);
for(i=(0);i<(As);i++){
a[i] = A[i];
}
int m7of8KOo = n2;
for(i=(As);i<(m7of8KOo);i++){
a[i].val = 0;
}
fft_L(n2, a, root, mem);
for(i=(0);i<(n2);i++){
a[i] *= a[i];
}
fftinv_L(n2, a, root, mem);
r = Mint(n2).inverse();
for(i=(0);i<(Rs);i++){
res[i] = a[i]*r;
}
}
int P;
int A[100000];
int B[100000];
int c[100000];
Mint x[100000];
Mint y[100000];
Mint z[200000];
int main(){
wmem = memarr;
int i;
int j;
int k;
int r;
rd(P);
{
int Lj4PdHRW;
for(Lj4PdHRW=(0);Lj4PdHRW<(P-1);Lj4PdHRW++){
rd(A[Lj4PdHRW]);
}
}
{
int e98WHCEY;
for(e98WHCEY=(0);e98WHCEY<(P-1);e98WHCEY++){
rd(B[e98WHCEY]);
}
}
r = primitiveRoot(P);
for(i=(0);i<(P-1);i++){
k = powmod(r,i,P);
x[i] = A[k-1];
y[i] = B[k-1];
}
convolution_L(x,P-1,y,P-1,z,2*P-2);
for(i=(0);i<(P-1);i++){
k = powmod(r,i,P);
c[k-1] = z[i] + z[i+P-1];
}
{
int KrdatlYV;
if(P-1==0){
putchar_unlocked('\n');
}
else{
for(KrdatlYV=(0);KrdatlYV<(P-1-1);KrdatlYV++){
wt_L(c[KrdatlYV]);
wt_L(' ');
}
wt_L(c[KrdatlYV]);
wt_L('\n');
}
}
return 0;
}
// cLay varsion 20191122-1 [beta]
// --- original code ---
// #define MD 998244353
// int P, A[1d5], B[1d5], c[1d5];
// Mint x[1d5], y[1d5], z[2d5];
// {
// int i, j, k, r;
// rd(P,A(P-1),B(P-1));
// r = primitiveRoot(P);
// rep(i,P-1){
// k = powmod(r,i,P);
// x[i] = A[k-1];
// y[i] = B[k-1];
// }
// convolution(x,P-1,y,P-1,z,2*P-2);
// rep(i,P-1){
// k = powmod(r,i,P);
// c[k-1] = z[i] + z[i+P-1];
// }
// wt(c(P-1));
// }
LayCurse