ループボリューム--K番目の大きいC-FFT


この問題は他の問題ステーションでは見つけられませんでしたが、ここに貼っておきました・・・
題意:与えられた配列a[N][M]とb[N]は、定義:ここでNは素数<2^18、M=2/3/4であり、K番目に大きいc[i]を求める.
まず、bを分類し、aをm個の配列に分解することが明らかになり、問題を以下の問題に変換することができます.
x[i]=Σy[j]z[i*j mod n]を求めます
ではnは素数であるため,nの原根gを求めると,任意のi∈[1,n)に対してg^p≡i(mod n)がある.
では,離散対数で問題を解決することができ,i=0とj=0は単独で処理できる.
x'[p]をx[i]とし、iをpをベースとしたnに関する離散対数とし、yとzについても同様の処理を行うと、以下のようになる.
x'[p]=∑y'[q]z'[p+q mod n-1]
このような問題に対して,y'[]をy'[],すなわちy'[i]=y'[n−1−i]に逆順にすることが明らかになった.
x'[p]=Σy'[n-1-q]z'[p+q mod n-1]
A[i]=Σy'[n-1-j]z'[i+j]を求めればよいのです
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
#define gch getchar() 
template
inline void read(integer&x){
	x=0;int f=1;char ch=gch;
	while(ch>'9'||ch='0'){x=x*10+ch-'0';ch=gch;}
	x*=f;
}

struct idouble{
	double r,i;
	idouble(double _r=0.0,double _i=0.0){r=_r,i=_i;}
	idouble operator +(const idouble&a)const{return idouble(r+a.r,i+a.i);}
	idouble operator -(const idouble&a)const{return idouble(r-a.r,i-a.i);} 
	idouble operator *(const idouble&a)const{return idouble(r*a.r-i*a.i,r*a.i+i*a.r);}
} ;

templatevoid rader(iint a[],int len){
	int i,j=len>>1,k;
	for(i=1;i>1;j>=k;j-=k,k>>=1);
		if(j>1,j=0;j>=1;
	}
	return re;
}

int tmp[10],cnt;

void init(){
	int i,j,p;
	read(n),read(m),read(K);
	for(i=0;i1)tmp[++cnt]=p;
	for(g=2;;g++){
		for(i=1;i<=cnt;i++)
			if(kuai(g,(n-1)/tmp[i],n)==1)
				break;
		if(i>cnt)break; 
	}
	for(i=0,j=1;i