UOJ#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强(循环卷积)

传送门

题解:
看做一个 n n 3 3 次方程在做循环卷积即可。

注意 3 3 次单位根可以直接扩域而不用去解三次剩余(只不过要卡常数)。

#include <bits/stdc++.h>
using namespace std;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
} 
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
inline void W(int x) {
	static int buf[50];
	if(!x)  {putchar('0'); return;}
	if(x<0) {putchar('-'); x=-x;}
	while(x) {buf[++buf[0]]=x%10; x/=10;}
	while(buf[0]) putchar(buf[buf[0]--]+'0');
}

const int N=1e6+50;
int m,t,mod,nw[15],c[15][15];
inline void exgcd(int a,int b,long long &x,long long &y) {b ? (exgcd(b,a%b,y,x),y-=a/b*x) : (x=1,y=0);}
inline int cinv(int a) {
	long long x,y;
	exgcd(a,mod,x,y);
	return (x%mod+mod)%mod;
}
struct num {
	int a,b;
	num(int a=0,int b=0) : a(a),b(b) {}
	friend inline num operator +(const num &a,const num &b) {return num((a.a+b.a)%mod,(a.b+b.b)%mod);}
	friend inline num operator *(const num &a,const num &b) {
		return num((1ll*a.a*b.a-3ll*a.b*b.b)%mod,
				   (1ll*a.b*b.a+1ll*a.a*b.b)%mod);
	}
	friend inline num power(num a,int b) {num c(1,0); for(;b;b>>=1,a=a*a) if(b&1) c=c*a; return c;}
} f[N],g[N],w[3];
inline int pos(int i,int j) {return i/nw[j]%3;}
inline void dft(num *a) {
	for(int i=0;i<m;i++)
		for(int j=0;j<nw[m];j++) if(!pos(j,i)) {
			num x=a[j], y=a[j+nw[i]], z=a[j+2*nw[i]];
			a[j]=x+y+z;
			a[j+nw[i]]=x+y*w[1]+z*w[2];
			a[j+nw[i]*2]=x+y*w[2]+z*w[1];
		}
}
int main() {
	m=rd(), t=rd(), mod=rd();
	nw[0]=1; for(int i=1;i<=m;i++) nw[i]=nw[i-1]*3;
	for(int i=0;i<nw[m];i++) f[i].a=rd();
	for(int i=0;i<=m;i++) for(int j=0;j<=m-i;j++) c[i][j]=rd();
	for(int i=0;i<nw[m];i++) {
		int u[3]; u[0]=u[1]=u[2]=0;
		for(int j=0;j<m;j++) u[pos(i,j)]++;
		g[i].a=c[u[1]][u[2]];
	} 
	w[0]=num(1,0); w[1]=num((mod-1)/2,(mod+1)/2); w[2]=w[1]*w[1];
	dft(f); dft(g);
	for(int i=0;i<nw[m];i++) f[i]=f[i]*power(g[i],t);
	swap(w[1],w[2]); dft(f);
	int inv=cinv(nw[m]);
	for(int i=0;i<nw[m];i++) W(1ll*(f[i].a+mod)*inv%mod), putchar('\n');
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83719451