「餘姚中學 2019 聯測 Day 2」Under Pressure(多項式類歐幾里得,DFT)

在這裏插入圖片描述

對於第ww位,我們實際上是要求一個多項式:
i=0AxBi+Ckw\sum_{i=0}^A x^{\left\lfloor \frac {Bi+C}{\small {k^w}} \right\rfloor}
我們知道類歐幾里得實際上很多時候是需要轉化爲二維直線下的所有點的點權和。
這個題也可以這樣轉化:
原式=
(i=0Aj=0Bi+Ckwxj)(x1)+A+1x\frac {(\sum_{i=0}^A \sum_{j=0}^{\left\lfloor \frac {Bi+C}{\small {k^w}} \right\rfloor} x^j)(x-1)+A+1}x
前面是逆用了等比數列求和公式。
那麼我們可以定義函數
F(n,a,b,c,p,q)=i=0nj=0Ai+BCxpixyjF(n,a,b,c,p,q)=\sum_{i=0}^n \sum_{j=0}^{\left\lfloor \frac {Ai+B}{\small C} \right\rfloor} x^{pi}x^{yj}
那麼在這裏插入圖片描述
因爲這個卷積是長度爲kk的循環卷積,根據卷積定理我們只需要求出kk次單位根,求出多項式在這kk個單位根的點值後IDFTIDFT即可得到多項式。
那麼求點值就簡單了,上面所有形如i=0aj=0bx\sum_{i=0}^a\sum_{j=0}^bx,i=0aj=0bix\sum_{i=0}^a \sum_{j=0}^{bi}x的點值都是可以O(1)O(1)計算的。(注意等比數列有公比爲1這個天坑)
等等,mod1e9+7\bmod 1e9+7哪來的kk次單位根?
因爲Ai1e9A_i \leq 1e9,所以我們隨便找一個1e9+1\geq 1e9+1的質數p=ka+1p = ka + 1來當模數,就可以保證精確算出多項式的係數的同時還有kk次單位根。
這個pp哪裏找呢?
直接從1e91e9以上forfor循環找即可,因爲質數密度是1lnx\frac {1}{\ln x}的,所以期望找ln1e9\ln 1e9次即可找到,可以O(1e9)O(\sqrt {1e9})判質數,可以寫一個MillerRabinMillerRabin壓壓驚。
然後再簡單找一下原根即可。
時間複雜度O(nklogk1e18(k+log1e9))O(nk\log_k{1e18}(k+\log 1e9))
時間複雜度的瓶頸在DFTDFT,請務必循環展開,實測有55倍的常數差距。

注:可以使用bluesteinbluestein算法來代替k2DFTk^2DFT,但是因爲這個是模意義下的DFTDFT,所以需要寫MTTMTT來避免精度流失(用NTTNTT兩個不同模數難以簡單切換),個人認爲是跑不過k2k^2循環展開的,歡迎大佬寫一發來吊打我。
AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 1005
#define LL long long
#define mod 998244353
using namespace std;

int n,K;
int t1 = clock() , ts = 0;

namespace Prime{
	int Pow(int b,int k,int p){
		int r = 1;
		for(;k;k>>=1,b=1ll*b*b%p)
			if(k&1)
				r=1ll*r*b%p;
		return r;
	}

	bool MR(int x){
		static int base[6] = {2 , 3 , 7 , 31 , 61 , 101};
		int r=x-1,t=0;
		for(;!(r&1);r>>=1,t++);
		for(int i=0;i<6;i++){
			int nw = Pow(base[i],r,x) , pr = 0;
			for(int k=0;k<t;k++){
				swap(nw , pr);
				if((nw = (1ll * pr * pr % x)) == 1 && pr != 1 && pr != x-1)
					return 0;
			}
			if(nw != 1) return 0;
		}
		return 1;
	}
}
using Prime::MR;

int P,w[maxn]={1},w_1[maxn]={0},r_1[maxn];
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%P) if(k&1) r=1ll*r*b%P; return r; }

void IDFT(int *A,int *B){
	static int r[maxn];
	for(int i=0;i<K;i++){
		int t = i ? w[K-i] : w[0];
		static int pw[9]={};
		for(int k=pw[0]=1;k<=8;k++) pw[k] = 1ll * pw[k-1] * t % P;
		r[i] = 0;
		int j = K-1;
		for(;j-7>=0;j-=8)
			r[i] = (1ll * r[i] * pw[8]
				+ 1ll * A[j] * pw[7]
				+ 1ll * A[j-1] * pw[6]
				+ 1ll * A[j-2] * pw[5]
				+ 1ll * A[j-3] * pw[4]
				+ 1ll * A[j-4] * pw[3]
				+ 1ll * A[j-5] * pw[2]
				+ 1ll * A[j-6] * pw[1]
				+ 1ll * A[j-7] * pw[0]) % P;
		for(;j>=0;j--)
			r[i] = (1ll * r[i] * t + A[j]) % P;
	}
	static int iv = Pow(K , P-2);
	for(int i=0;i<K;i++) 
		B[i] = r[i] * 1ll * iv % P;
}

int tot[5]={};
void F(int n,LL A,LL B,LL C,int p,int q,int *f){
	if(n < 0) return;
	if(B >= C){
		LL b = B / C;
		F(n,A,B%C,C,p,q,f);
		for(int i=1;i<K;i++){
			int iq = 1ll * i * q % K , ip = 1ll * i * p % K , biq = 1ll * b * iq % K;
			int x = ip ? r_1[ip] * 1ll * w_1[1ll * ip * (n+1) % K] % P :
						n+1,
				y = iq % K ? r_1[iq] * 1ll * w_1[biq] % P :
						b;
			f[i] = (1ll * f[i] * w[biq] + 1ll * x * y) % P;
		}
		return;
	}
	if(A >= C){
		LL a = A / C;
		F(n,A%C,B,C,(p+1ll*a*q)%K,q,f);
		for(int i=1;i<K;i++){
			int iq = 1ll * i * q % K , ip = 1ll * i * p % K;
			if(iq){
				int x = (p + 1ll * a * q) % K , xi = 1ll * i * x % K;
				x = xi ? w_1[1ll * xi * (n+1ll) % K] * 1ll * r_1[xi] % P : n+1;
				int y = ip ? w_1[1ll * ip * (n+1ll) % K] * 1ll * r_1[ip] % P : n + 1;
				f[i] = (f[i] + 1ll * (x - y) * r_1[iq]) % P;
			}
			else{
				if(ip == 0)
					f[i] = (f[i] + 1ll * a * (n * (n+1ll) / 2 % P)) % P;
				else{
					f[i] = (f[i] - (1ll * w_1[1ll * ip * n % K] * w[ip] % P * r_1[ip] 
						- 1ll * n * w[1ll * ip * (n+1ll) % K]) % P * r_1[ip] % P * a
						) % P;
				}
			}
		}
		return; 
	}
	if(! A){
		LL b = B / C + 1;
		for(int i=1;i<K;i++){
			int iq = 1ll * i * q % K , ip = 1ll * i * p % K;
			int x = ip ? r_1[ip] * 1ll * w_1[1ll * ip * (n+1) % K] % P :
						n+1,
				y = iq ? r_1[iq] * 1ll * w_1[1ll * iq * b % K] % P :
						b;
			f[i] =  1ll * x * y % P;
		}
		return;
	}
	LL T = (1ll*A*n+B)/C , R = (1ll * A * n + B) % C , nT = floor(((n + 1ll) * A - R - 1.0) / C) , np = (K-p)%K , nq = (K-q)%K;
	F(nT,C,R,A,nq,np,f);
	for(int i=1;i<K;i++){
		int nqi = 1ll * nq * i % K , npi = 1ll * np * i % K;
		int x = nqi ? w[1ll * (nT+1) * nqi % K] * 1ll * w_1[1ll * (T-nT) * nqi % K] % P * r_1[nqi] % P : 
					 T - nT;
		int y = npi % K ? w_1[1ll * (n + 1) * npi % K] * 1ll * r_1[npi] % P : n + 1;
		f[i] = 1ll * (f[i] + 1ll * x * y % P) * w[(1ll * p * n + 1ll * q * T) % K * i % K] % P;
	}
}

int main(){ 
	scanf("%d%d",&n,&K);
	static int fn[maxn],A[maxn],B[maxn],C[maxn];
	for(int i=0;i<K;i++) scanf("%d",&fn[i]);
	LL mx = 0;
	for(int i=1;i<=n;i++) scanf("%d%d%d",&A[i],&B[i],&C[i]),mx=max(mx,A[i]*1ll*B[i]+C[i]);
	for(P=ceil(1000000002.0/K)*K+1;!MR(P);P+=K);
	vector<int>pr;
	int t = P - 1;
	for(int i=2;i*i<=t;i++)
		if(t % i == 0){
			pr.push_back(i);
			for(;t % i == 0;t /= i);
		}
	if(t > 1) pr.push_back(t);
	for(int i=2;;i++){
		bool flg = 0;
		for(int j=0;j<pr.size();j++)
			if(Pow(i,(P-1) / pr[j]) == 1){
				flg = 1;
				break;
			}
		if(!flg){
			w[1] = Pow(i,(P-1) / K);
			break;
		}
	}
	for(int i=1;i<K;i++) w[i] = 1ll * w[i-1] * w[1] % P , w_1[i] = w[i] - 1 , r_1[i] = Pow(w_1[i],P-2);
	int ans = 0;
	
	for(LL k=1;k<=mx && k>=0;k=k*K){
		static int g[maxn]={};
		for(int i=0;i<K;i++) g[i] = 1;
		for(int i=1;i<=n;i++){
			static int f[maxn]={};
			memset(f,0,sizeof f);
			f[0] = A[i] + 1;
			if(A[i] * 1ll * B[i] + C[i] >= k){
				F(A[i],B[i],C[i],k,0,1,f);
				for(int p=1;p<K;p++)
					f[p] = (f[p] * (w[p] - 1ll) % P + A[i] + 1) * w[(K-p) % K] % P;
				IDFT(f,f);		
			}
			for(int j=0;j<K;j++){
				f[j] = (f[j] + P) % P;
				f[j] = (f[j] + (j ? f[j-1] : 0)) % mod;
				g[j] = 1ll * g[j] * f[j] % mod;
			}
		}
		for(int i=1;i<K;i++)
			ans = (ans + 1ll * (g[i] - g[i-1]) * fn[i]) % mod;
	}
	printf("%d\n",(ans+mod)%mod);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章