ループボリューム--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]を求めればよいのです
題意:与えられた配列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