CQOI2016 day2 模拟赛总结

T1
N=pq
r=(p-1)(q-1)
ed=1(mod r)
c^d=n(mod N)
第一步rho,第二步直接算
第三步exgcd,第四步快速幂
强行算就可以了
exgcd忘开longlong 100->30
T2
蜜汁题意
读懂过后发现建字典树
然后随便维护个单调栈搞搞就OK了
时间nlogn
T3
每次考虑把最大的出堆,把次大的入堆
hash去重
这样是31*k*log的
很慢对不对,我们考虑把31搞到可持久化线段树里面
这样每次修改就只用修改一条链了= =
可是要hash去重。。。开个hashmap就好
然后常数卡不下来了QAQ bzoj只给10s不让人活啦
所以还是要好好学其他人的神奇方法。。。


day2 30+100+60
第一个30纯属脑抽


//Copyright(c)2016 liuchenrui
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL e,N,c,p,q,n,d,r;
LL ksc(LL a,LL b,LL c){
	LL ans=0;
	while(b){
		if(b&1LL){
			ans=ans+a;
			if(ans>=c)ans-=c;
		}
		b>>=1LL;
		a=a+a;if(a>=c)a-=c;
	}
	return ans;
}
LL ksm(LL a,LL b,LL c){
	LL ans=1;
	while(b){
		if(b&1LL){
			ans=ksc(ans,a,c);
		}
		b>>=1LL;
		a=ksc(a,a,c);
	}
	return ans;
}
LL exgcd(LL a,LL b,LL &x,LL &y){
	if(b==0){
		x=1;y=0;return a;
	}
	LL z=exgcd(b,a%b,x,y);
	LL t=x;x=y;y=t-a/b*y;
	return z;
}
int windows_rand(){
	return rand()&32767;
}
LL gcd(LL a,LL b){
	return b==0?a:gcd(b,a%b);
}
LL prho(LL c,LL n){
	LL i,x,y,k,d;
	i=1;
	x=y=windows_rand()%n;
	k=2;
	do{
		i++;
		d=gcd(n+y-x,n);
		if(d>1&&d<n)return d;
		if(i==k)y=x,k<<=1LL;
		x=(ksc(x,x,n)+n-c)%n;
	}while(y!=x);
	return n;
}
void rho(LL n){
	LL t=n;
	while(t>=n){
		t=prho(windows_rand()%(n-1)+1,n);
	}
	p=t;q=N/t;return;
}
int main(){
	freopen("crack.in", "r",stdin);
	freopen("crack.out","w",stdout);
	cin>>e>>N>>c;
	rho(N);
	r=(p-1)*(q-1);
	LL p;
	exgcd(e,r,d,p);
	d=((d%r)+r)%r;
	cout<<d<<" "<<ksm(c,d,N)<<endl;
}


#include<bits/stdc++.h>
using namespace std;
void splay(int &v){
	char s=getchar();v=0;
	while(s>'9'||s<'0')s=getchar();
	while(s>='0'&&s<='9')v=v*10+s-'0',s=getchar();
}
int son[32000000][2],t[32000000],tot,cnt;

int main(){
	freopen("route.in","r",stdin);
	freopen("route.out","w",stdout);
	
	int q;splay(q);
	for(;q--;){
		static char op[4];
		static int s[35],dl[35];
		scanf("%s",op+1);
		if(op[1]=='Q'){
			int a,b,c,d,l,r;
			splay(a),splay(b),splay(c),splay(d),splay(l),splay(r);
			for(int i=8 ;i>=1 ;i--)s[i]=a&1,a>>=1;
			for(int i=16;i>=9 ;i--)s[i]=b&1,b>>=1;
			for(int i=24;i>=17;i--)s[i]=c&1,c>>=1;
			for(int i=32;i>=25;i--)s[i]=d&1,d>>=1;
			int now=0,ans=0,top=0;
			for(int i=1;i<=32;i++){
				now=son[now][s[i]];
				if(t[now]){
					while(top&&t[now]<dl[top])top--;
					dl[++top]=t[now];
				}
				if(now==0)break;
			}
			for(int i=1;i<=top;i++){
				if(l<=dl[i] && dl[i]<=r)ans++;
			}
			printf("%d\n",ans);
		}
		else{
			cnt++;
			int a,b,c,d,p;
			splay(a),splay(b),splay(c),splay(d),splay(p);
			for(int i=8 ;i>=1 ;i--)s[i]=a&1,a>>=1;
			for(int i=16;i>=9 ;i--)s[i]=b&1,b>>=1;
			for(int i=24;i>=17;i--)s[i]=c&1,c>>=1;
			for(int i=32;i>=25;i--)s[i]=d&1,d>>=1;
			int now=0;
			for(int i=1;i<=p;i++){
				if(!son[now][s[i]])son[now][s[i]]=++tot;
				now=son[now][s[i]];
			}
			t[now]=cnt;
		}
	}
}


//liuchenrui
#include<bits/stdc++.h>
#include<hash_map>
#define LL long long
#define H 1000001007ULL
#define ULL unsigned long long
#define ld long double
using namespace std;
LL n;int k;
bool ispri[140];
int pri[140],tot;
ULL h[35];
int root[2000000],ls[20000000],rs[20000000],cnt;
LL ji[20000010];ULL hash[20000000];
int num[55];
struct node{
	int id;
	friend bool operator < (const node &a,const node &b){
		return ji[root[a.id]]<ji[root[b.id]];
	}
};
namespace __gnu_cxx{
	template<> struct hash<ULL>{
		size_t operator()(ULL x) const{
			return x;
		}
	};
}
__gnu_cxx::hash_map<ULL,bool>s;
void build(int &now,int l,int r,int pos,int v,LL f){
	now=++cnt;
	if(l==r){
		if(l==pos)hash[now]=v,ji[now]=f;
		else ji[now]=1;
		return;
	}
	int mid=l+r>>1;
	build(ls[now],l,mid,pos,v,f),build(rs[now],mid+1,r,pos,v,f);
	hash[now]=hash[ls[now]]*(h[r-mid])+hash[rs[now]];
	ji[now]=ji[ls[now]]*ji[rs[now]];
}
void getval(int now,int l,int r){
	if(l==r){
		num[l]=hash[now];
		return;
	}
	int mid=l+r>>1;
	getval(ls[now],l,mid);
	getval(rs[now],mid+1,r);
}
void insert(int pre,int &now,int l,int r,int pos,int v){
	if(!now)now=++cnt;
	if(l==r){
		hash[now]=v;
		LL t=1;
		for(int i=1;i<=v;i++){
			t*=(LL)pri[pos];
		}
		ji[now]=t;
		return;
	}
	int mid=l+r>>1;
	if(pos<=mid){
		if(ls[pre]==ls[now])ls[now]=0;
		insert(ls[pre],ls[now],l,mid,pos,v);
		if(!rs[now])rs[now]=rs[pre];
	}
	else{
		if(rs[pre]==rs[now])rs[now]=0;
		insert(rs[pre],rs[now],mid+1,r,pos,v);
		if(!ls[now])ls[now]=ls[pre];
	}
	hash[now]=hash[ls[now]]*(h[r-mid])+hash[rs[now]];
	ji[now]=ji[ls[now]]*ji[rs[now]];
}
ULL gethash(ULL prehash,int pos){
	prehash-=h[31-pos];
	if(pos!=1)prehash+=h[32-pos];
	return prehash;
}
int main(){
	freopen("smooth.in","r",stdin);
	freopen("smooth.out","w",stdout);
	cin>>n>>k;
	for(int i=2;i<=128;i++){
		if(!ispri[i]){
			for(int j=i+i;j<=128;j+=i){
				ispri[j]=1;
			}
			pri[++tot]=i;
		}
	}
	h[0]=1;
	for(int i=1;i<=32;i++){
		h[i]=h[i-1]*H;
	}
	priority_queue<node>que;
	for(int i=1;i<=31;i++){
		ld x=1;int lim;
		for(int j=1;;j++){
			x*=(ld)pri[i];
			if(x>n){
				lim=j-1;break;
			}
		}
		LL y=1;
		for(int j=1;j<=lim;j++){
			y*=(LL)pri[i];
		}
		build(root[i],1,31,i,lim,y);
		que.push((node){i});
		s[hash[root[i]]]=1;
	}
	int rcnt=31;
	for(int T=1;T<k;T++){
		int f=que.top().id;que.pop();
		ULL nh=hash[root[f]];
		getval(root[f],1,31);
		for(int i=1;i<=31;i++){
			if(num[i]&&!s[gethash(nh,i)]){
				s[gethash(nh,i)]=1;
				++rcnt;
				insert(root[f],root[rcnt],1,31,i,num[i]-1);
				if(i!=1)insert(root[f],root[rcnt],1,31,i-1,num[i-1]+1);
				que.push((node){rcnt});
			}
		}
	}
	printf("%lld\n",ji[root[que.top().id]]);
	cerr<<clock()<<endl<<rcnt<<endl;
}

最后那个会T,所以你懂得

你可能感兴趣的:(数学,hash,字典树,单调栈,xianduanshu)