BZOJ3557: [Ctsc2014]随机数

BZOJ上数据范围没写清楚,实际数据范围如这个表格所示。


把$M_n$和$x$看成$\mathbb{F}_2$下的$m$维的列向量,则有转移矩阵 $$A = \begin{pmatrix} 0 & 0 & \cdots & 0 & -x_0\\ 1 & 0 & \cdots & 0 & -x_1\\ 0 & 1 & \cdots & 0 & -x_2\\ \vdots & \vdots & \ddots & \vdots & \vdots\\ 0 & 0 & \cdots & 1 & -x_{m-1}\\ \end{pmatrix}$$ 该矩阵为多项式 $$p(z) = z^m+\sum_{i=0}^{m-1}x_iz^i$$ 的友阵。因此,若把$M_n$看成$F$中的元素,则有 $$M_n(z) = z^nM_0(z)$$ 其中$F = \mathbb{F}_2[z]/(p(z))$为模$p(z)$意义下的$\mathbb{F}_2$上的多项式构成的环。当然,也可以直接通过观察得出这个结论。注意到$n < m$时$F$中的$z^n$与$\mathbb{F}_2[z]$中的相同,于是可以以复杂度 $$O\bigl(m\log m\max(1,\log k-\log m)\bigr)$$ 解决第一种情况。

所有$2^m-1$个非零元素都能被生成,是数列在这些元素中等概率取值的必要条件。该条件成立时有 $$\begin{aligned} 2^m-1 &= |\mathopen{<}z\mathclose{>}M_0(z)| = |\mathopen{<}z\mathclose{>}|\\ &\le |F^\times| \le |F \setminus \{0\}| = 2^m-1 \end{aligned}$$ 其中$F^\times$为$F$中所有有乘法逆元的元素构成的乘法群。由此得$\mathopen{<}z\mathclose{>} = F^\times = F \setminus \{0\}$,那么$F$为大小为$2^m$的有限域,且$\forall f(z) \in F^\times$,有$(f(z))^{2^m} = f(z)$,故 $$\begin{aligned} M_k(z) &= (z^{k \cdot 2^l})^{2^{m-l}}M_0(z)\\ &= \Bigl(M_{k \cdot 2^l}(z)\bigl(M_0(z)\bigr)^{-1}\Bigr)^{2^{m-l}}M_0(z)\\ &= \bigl(M_{k \cdot 2^l}(z)\bigr)^{2^{m-l}}\Bigl(\bigl(M_0(z)\bigr)^{2^{m-l}}\Bigr)^{2^l-1}\\ \end{aligned}$$ 从而可以以复杂度$O(m^2\log m)$解决第二种情况。

由上述推导可知,$x$是好的等价于$F$是一个域,且$z$是$F^\times$的生成元。$F$是一个域当且仅当$p(z)$是$\mathbb{F}_2$上的既约多项式。由此,或许可以用某些方法生成第二种情况的数据。


这题挺好写的,就一多项式除法就没了,不知道为啥没几个人写。

#include<algorithm>
#include<vector>
#include<cstdio>
#define RAN(a)a.begin(),a.end()
using namespace std;
typedef unsigned long long u64;
typedef unsigned u32;
namespace num{
	const u32 p=1811939329;
	const u32 g=13;
	inline u32 imod(u32 a){
		return a<p?a:a-p;
	}
	inline u32 ipow(u32 a,u32 n){
		u32 s=1;
		for(;n;n>>=1){
			if(n&1)
				s=(u64)s*a%p;
			a=(u64)a*a%p;
		}
		return s;
	}
	inline u32 inv(u32 a){
		return ipow(a,p-2);
	}
}
using namespace num;
class poly_base{
public:
	vector<u32>a;
	poly_base(){}
	explicit poly_base(int n):a(n){}
	void fft(int n,bool f){
		a.resize(n);
		if(n<=1)
			return;
		for(int i=0,j=0;i<n;++i){
			if(i<j)
				std::swap(a[i],a[j]);
			int k=n>>1;
			while((j^=k)<k)
				k>>=1;
		}
		vector<u32>w(n/2);
		w[0]=1;
		for(int i=1;i<n;i<<=1){
			for(int j=i/2-1;~j;--j)
				w[j<<1]=w[j];
			int m=(p-1)/i/2;
			u64 s=ipow(g,f?p-1-m:m);
			for(int j=1;j<i;j+=2)
				w[j]=s*w[j-1]%p;
			for(int j=0;j<n;j+=i<<1){
				u32*b=&a[0]+j,*c=b+i;
				for(int k=0;k<i;++k){
					u32 v=(u64)w[k]*c[k]%p;
					c[k]=imod(b[k]+p-v);
					b[k]=imod(b[k]+v);
				}
			}
		}
	}
	void dft(int n){
		fft(n,0);
	}
	void idft(){
		int n=a.size();
		fft(n,1);
		u64 f=inv(n);
		for(int i=0;i<n;++i)
			a[i]=f*a[i]%p;
	}
};
class poly:public poly_base{
public:
	poly(){}
	explicit poly(int n):poly_base(n){}
	u32&operator[](int i){
		return a[i];
	}
	const u32&operator[](int i)const{
		return a[i];
	}
	int size()const{
		return a.size();
	}
	void swap(poly&b){
		a.swap(b.a);
	}
	static int len(int n){
		while(n^n&-n)
			n+=n&-n;
		return n;
	}
	void fix(){
		while(size()&&!a.back())
			a.pop_back();
	}
	void mul(poly b){
		fix();
		b.fix();
		int n=len(size()+b.size()-1);
		dft(n);
		b.dft(n);
		for(int i=0;i<n;++i)
			a[i]=(u64)a[i]*b[i]%p;
		idft();
		for(int i=0;i<n;++i)
			a[i]&=1;
		fix();
	}
	void sqr(){
		fix();
		int n=len(2*size()-1);
		dft(n);
		for(int i=0;i<n;++i)
			a[i]=(u64)a[i]*a[i]%p;
		idft();
		for(int i=0;i<n;++i)
			a[i]&=1;
		fix();
	}
	void mod(int n){
		a.resize(n);
	}
	void inv(int n){
		int m=len(n);
		mod(m);
		vector<u32>b(1,1);
		a.swap(b);
		for(int i=2;i<=m;i<<=1){
			poly c(i);
			for(int j=0;j<i;++j)
				c[j]=b[j];
			sqr();
			mul(c);
			mod(i);
		}
		mod(n);
	}
	void div(poly b){
		fix();
		b.fix();
		int n=size()-b.size()+1;
		if(n<=0){
			a.clear();
			return;
		}
		reverse(RAN(a));
		mod(n);
		reverse(RAN(b.a));
		b.inv(n);
		mul(b);
		mod(n);
		reverse(RAN(a));
		fix();
	}
	void mod(poly b){
		fix();
		b.fix();
		int m=b.size();
		if(size()>=m){
			poly c=*this;
			div(b);
			mul(b);
			mod(m-1);
			for(int i=0;i<m-1;++i)
				a[i]^=c[i];
			fix();
		}
	}
};
struct ano{
	operator u64(){
		u64 x=0;
		signed c=getchar();
		while(c<48)
			c=getchar();
		while(c>47)
			x=x*10+c-48,c=getchar();
		return x;
	}
}buf;
poly basis(int n){
	poly a(n+1);
	a[n]=1;
	return a;
}
int main(){
	int n=buf;
	poly p(n+1);
	p[n]=1;
	for(int i=0;i<n;++i)
		p[i]=buf;
	poly s(n);
	for(int i=0;i<n;++i)
		s[i]=buf;
	if(buf==0){
		u64 k=buf;
		if(k<n){
			s.mul(basis(k));
			s.mod(p);
		}else{
			int i=0;
			while((k&(2<<i)-1)<n)
				++i;
			s.mul(basis(k&(1<<i)-1));
			s.mod(p);
			poly a=basis(1<<i);
			k>>=i;
			for(;k;k>>=1){
				if(k&1){
					s.mul(a);
					s.mod(p);
				}
				if(k>1){
					a.sqr();
					a.mod(p);
				}
			}
		}
	}else{
		int l=buf%n;
		poly a(n);
		for(int i=0;i<n;++i)
			a[i]=buf;
		s.swap(a);
		for(int i=0;i<n-l;++i){
			s.sqr();
			s.mod(p);
			a.sqr();
			a.mod(p);
		}
		for(int i=0;i<l;++i){
			s.mul(a);
			s.mod(p);
			if(i<l-1){
				a.sqr();
				a.mod(p);
			}
		}
	}
	s.mod(n);
	for(int i=0;i<n;++i)
		printf("%d",s[i]);
	puts("");
}

Rewrited @ 姫野星奏生誕祭2019

Edited @ 2019-06-28

posted @ 2016-06-03 16:49  f321dd  阅读(435)  评论(0编辑  收藏  举报