循环卷积 -- 第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'){if(ch=='-')f=-1;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



你可能感兴趣的:(数学,-,多项式及生成函数)