bzoj3557: [Ctsc2014]随机数

常数优化数次后终于卡过去了,感人肺腑。成功get rank last。

orz出题人clj:

http://download.noi.cn/T/2014/CCF_CTSC2014.rar 解压密码CCfCtsC2014

orz神犇们的题解以及常数优化技巧:

http://blog.miskcoo.com/2015/05/bzoj-3557

http://cjjlsdy.blog.163.com/blog/static/180370563201461133026/

http://picks.logdown.com/posts/197310-solution-to-ctsc2014-random

http://vfleaking.blog.163.com/blog/static/1748076342014421105221134/

顺便吐槽一句对拍的时候发现这几份代码输出不一样。

简要说一下做法:

每个数可以看做GF(2)下的多项式,则mk=m0*x^k (mod x^m+X)。

需要多项式取模,blog.miskcoo.com及picks.logdown.com里有讲解。

那么第一问FFT+快速幂,第二问由于x是好的,则x是mod x^m+X意义下的群的生成元,那么x=x^2^m,多项式a的逆元即为a^(2^m-2),求个逆元即可。

为优化常数可以在n较小时用压位乘法而不用FFT(orz vfk)

#include<bits/stdc++.h>
#define N (1<<21)
using namespace std;
struct vec{
	double x,y;
	vec(double x=0,double y=0)
	:x(x),y(y){}
};
vec operator+(vec a,vec b){
	return vec(
	a.x+b.x,a.y+b.y);
}
vec operator-(vec a,vec b){
	return vec(
	a.x-b.x,a.y-b.y);
}
vec operator*(vec a,vec b){
	return vec(
	a.x*b.x-a.y*b.y,
	a.x*b.y+a.y*b.x);
}
void fft(vec* q,int n,int m){
	int i,j,k;
	for(i=j=0;i!=n;++i){
		if(i<j)
			swap(q[i],q[j]);
		for(k=n>>1;
		(j^=k)<k;k>>=1);
	}
	for(i=2;i<=n;i<<=1){
		double a(2*m
		*acos(-1)/i);
		vec s(cos(a),sin(a));
		for(j=0;j!=n;j+=i){
			vec t=1;
			for(k=j;k!=j+i/2;
			t=t*s,++k){
				vec u=q[k];
				vec v=t*q[k+i/2];
				q[k]=u+v;
				q[k+i/2]=u-v;
			}
		}
	}
	if(!~m)
		for(i=0;i!=n;++i)
			q[i].x/=n;
}
int* mem(int k){
	return (int*)calloc(k,4);
}
struct pol{
	int k,*u;
	pol(int v=0,int s=N)
	:k(1),u(mem(s)){u[0]=v;}
	~pol(){free(u);}
	int& operator[](int i){
		return u[i];
	}
	pol& operator=(int v){
		k=1,u[0]=v;
		return *this;
	}
	pol& operator=(pol& v){
		memcpy(u,v.u,(k=v.k)*4);
		return *this;
	}
	pol& operator+=(pol& v);
	pol& operator*=(pol& v);
};
int get(int k){
	int i=1;
	for(;i<k;i<<=1);
	return i;
}
pol& pol::operator+=(pol& v){
	for(int i=0;i!=k;++i)
		u[i]=u[i]+v[i]&1;
	return *this;
}
pol& pol::operator*=(pol& v){
	if(!k||!v.k)
		return *this=0;
	int i,j,n=k,m=v.k;
	k+=m-1;
	if(k<=1e4){
		typedef unsigned
		long long ds[200];
		static ds s,t;
		int q=k+63>>6;
		fill(s,s+q,0);
		fill(t,t+q,0);
		for(i=0;i!=m;++i)
			s[i>>6]|=0ull
			+v[i]<<(i&63);
		for(i=0;i!=n;++i){
			if(u[i])
				for(j=0;j!=q;++j)
					t[j]^=s[j];
			for(j=q-1;j;--j)
				s[j]=s[j]<<1
				|s[j-1]>>63&1;
			s[0]<<=1;
		}
		for(i=0;i!=k;++i)
			u[i]=t[i>>6]>>(i&63)&1;
	}else{
		static vec s[N],t[N];
		j=get(k);
		copy(u,u+n,s);
		copy(v.u,v.u+m,t);
		fill(s+n,s+j,0);
		fill(t+m,t+j,0);
		fft(s,j,1);
		fft(t,j,1);
		for(i=0;i!=j;++i)
			s[i]=s[i]*t[i];
		fft(s,j,-1);
		for(i=0;i!=k;++i)
			u[i]=int(s[i].x+.5)&1;
	}
	return *this;
}
void mov(pol& a,int k){
	if(a.k<k)
		fill(a.u+a.k,a.u+k,0);
	a.k=k;
}
void inv(pol& u,pol& v,int k){
	if(k<=1)v=k;
	else{
		int m=k+1>>1;
		inv(u,v,m);
		mov(v*=v,k);
		mov(v*=u,k);
	}
}
int fix(pol& a){
	while(a.k&&!a[a.k-1])
		--a.k;
	return a.k;
}
void rev(pol& u,pol& v,int k){
	reverse_copy(
	u.u,u.u+u.k,v.u);
	v.k=u.k,mov(v,k);
}
void print(pol& a,
const char* s=""){
	printf("%s",s);
	for(int i=0;i!=a.k;++i)
		printf("%d ",a[i]);
	putchar(10);
}
void div(pol& a,pol& b,pol& d,pol& r){
	if(fix(a)<fix(b))
		d=0,r=a;
	else{
		static pol u,v;
		int k=a.k-b.k+1;
		rev(a,d,k);
		rev(b,u,k);
		inv(u,v,k);
		mov(d*=v,k);
		reverse(d.u,d.u+k);
		r=b,r*=d;
		mov(r,b.k-1),r+=a;
	}
}
void gcd(pol& a,pol& b,pol& x,pol& y){
	if(!fix(b))
		x=1,y=0;
	else{
		pol u(0,1<<11);
		pol v(0,1<<11);
		div(a,b,u,v);
		gcd(b,v,y,x);
		u*=x,mov(y,max(
		y.k,u.k)),y+=u;
	}
}
void mul(pol& a,pol& b,pol& p){
	if(!a.k||!b.k){
		a=0;return;
	}
	int i,j,k=a.k+b.k-1;
	if(k<p.k){
		a*=b;return;
	}
	if(k<=1e4){
		typedef unsigned
		long long ds[200];
		static ds s,t,u;
		int q=k+63>>6;
		fill(s,s+q,0);
		fill(t,t+q,0);
		for(i=0;i!=b.k;++i)
			s[i>>6]|=0ull
			+b[i]<<(i&63);
		for(i=0;i!=p.k;++i)
			u[i>>6]|=0ull
			+p[i]<<(i&63);
		for(i=0;i!=a.k;++i){
			if(a[i])
				for(j=0;j!=q;++j)
					t[j]^=s[j];
			for(j=q-1;j;--j)
				s[j]=s[j]<<1
				|s[j-1]>>63&1;
			s[0]<<=1;
			if(s[(p.k+63>>6)-1]
			>>(p.k-1&63)&1)
				for(j=0;j!=q;++j)
					s[j]^=u[j];
		}
		a.k=p.k-1;
		for(i=0;i!=a.k;++i)
			a[i]=t[i>>6]>>(i&63)&1;
	}else{
		static pol u,v;
		u=a;
		div(u*=b,p,v,a);
	}
}
void inv(pol& a,int m,pol& p){
	static pol u;
	u=a,a=1;
	while(--m){
		mul(u,u,p);
		mul(a,u,p);
	}
}
template<class T>
inline void scan(T& x){
	static int u;
	x=0;
	while((u=getchar())<48);
	do
		x=x*10+u-48;
	while((u=getchar())>32);
}
int main(){
	pol a,m0,u,v,x;
	int i,m,l,q;
	long long k;
	scan(m);
	for(i=0;i!=m;++i)
		scan(x[i]);
	for(i=0;i!=m;++i)
		scan(m0[i]);
	x.k=m0.k=m;
	x[x.k++]=1;
	if(scan(q),q){
		scan(l);
		for(i=0;i!=m;++i)
			scan(a[i]);
		a.k=m;
		inv(u=m0,m,x);
		mul(a,u,x);
		for(i=0;i!=m-l;++i)
			mul(a,a,x);
	}else{
		a=u[1]=1,u.k=2;
		scan(k);
		for(;k;k>>=1){
			if(k&1)
				mul(a,u,x);
			if(k>>1)
				mul(u,u,x);
		}
	}
	mul(m0,a,x);
	for(i=0;i!=m;++i)
		putchar(m0[i]+48);
	putchar(10);
}

  

时间: 2024-11-10 13:44:53

bzoj3557: [Ctsc2014]随机数的相关文章

shell系列生成随机数的方法

一: RANDOM echo $RANDOM RANDOM的随机数是有范围的1--32767,一般用它是可以被破解的 1.2  生成八位数的随机密码: echo $(($RANDOM+11111111)) 二:MD5sum 随机加密方法 生成的密码较长 取9位数密码: echo $RADDOM |md5sum|cut -c 2-9 三:通过openssl产生随机数 [[email protected] tmp]# openssl rand -base64 8 hInfIvtfOSk= [[ema

javaScript随机数取值方法

Math.random()方法返回0到1之间的一个随机数,不包括0和1 如若想取的一个范围的随机数可套用下面的公式: 一.X+开始数-1=结束数 二.Math.floor(Math.random()*X+开始数) 注:Math.floor()向下舍入,去掉小数点后数 例: //若想取的5到10之间的数,套用公式:①X+开始数-1=结束数//可得出X为6//②Math.floor(Math.random()*X+开始数)//for(var i=0;i<10;i++){ document.write

重复10个1~60顺序且不重复的随机数

$flag = 1; for ($i = 0; $i < 10; $i++) {     $data['mobile'] = $evaluate_mobile;     //随机时间     $second = rand($flag, 6 * ($i + 1));//重复10个1~60顺序且不重复的随机数     $flag = $second + 1;//加1是未免与上一结果重复     $data['second'] = $second;     $result[] = $data; }

r语言之生成随机序列,随机数生成函数及用法

(1)生成正态分布随机数: rnorm(n,mean,sd)     其中,n表示生成的随机数个数,mean表示正态分布均值,sd表示正态分布标准差 > rnorm(5,0,2)[1] -5.31147765 0.09634197 0.35276104 -1.94548466 0.54533883 (2)生成均匀分布随机数: runif(n,min,max)     其中,n表示生成的随机数个数,min表示均匀分布最小值,max表示均匀分布最大值 > runif(5,0,10)[1] 9.74

随机数和随机数种子(转)

在计算机中并没有一个真正的随机数发生器,但是可以做到使产生的数字重复率很低,这样看起来好象是真正的随机数,实现这一功能的程序叫伪随机数发生器. 有关如何产生随机数的理论有许多,如果要详细地讨论,需要厚厚的一本书的篇幅.不管用什么方法实现随机数发生器,都必须给它提供一个名为“种子”的初始值.而且这个值最好是随机的,或者至少这个值是伪随机的.“种子”的值通常是用快速计数寄存器或移位寄存器来生成的. 下面讲一讲在C语言里所提供的随机数发生器的用法.现在的C编译器都提供了一个基于ANSI标准的伪随机数发

六爻预测等各种预测术的本质探讨之随机数猜想

对于各类预测术,比如六爻术,源于周易八卦.大家对预测术的观点泾渭分明,要么很相信,要么很不屑.或者有些人认为信则有不信则无. 当然我本人是信奉现代科学的,不过预测术确实有不可思议的地方,对过去和未来的分析不是简单的一句"巧合,概率论"能说的过去的.现经过本人的一番分析,试图对各类预测术的本质来个大起底. 其实,预测术不神奇,更不是有什么鬼神之力.而且也不能说古人比现在人更聪明.预测术的外圈是遵循一定规律的一整套规则,这些规则是古代在不停的经验总结中逐步完善的.换句话说,只要你自己能遵循

SQL Server生成指定范围内的随机数

在开发中很多时候,我们都会遇到这种需要生成一个指定范围随机数的情况.而且在很多语言中比如Java.C#.SQl等,都会有一个函数生成一个类似于0.234273983423789的随机小数,而所有的随机数都是通过这个最基本的随机数(0.234273983423789)变化过来的. 下面我说一下生成指定范围随机数的思路,比如我要生成一个100-999范围内的随机数,我就要保证我写的生成随机数的表达式所生成的值,最大是999,最小是100.还有就是要明白一个数学里的小道理,0.99去乘一个数字所得的结

Spring Boot? 配置文件详解:自定义属性、随机数、多环境配置等

自定义属性与加载 我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义: application-dev.yml com.didispace.blog: name: 程序猿DD title: Spring Boot教程 desc: ${com.didispace.blog.name}正在努力写<${com.didispace.blog.title}> # 随机字符串 value: ${random.value} # 随机int number: ${

牛客网华为机试训练第3题 明明的随机数

今天花了一下午才把明明的随机数这个搞明白,期间和牛客网的编译器殊死搏斗.一直发现在本地编译器运行成功,但是在牛客上的老师不能通过.整的十分的恼火和焦躁.后来看到了相同的问题,才发现解决之道. 时间限制:1秒 空间限制:32768K 热度指数:222608 本题知识点: 数组 算法知识视频讲解 题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不