CTSC2008AOYUNCHOUJIANG

题目描述

给出一个集合lucky

已知这个集合只可能包含2~6的整数

有一个集合L

一个元素i属于L当且仅当i属于lucky或者i=jk且j,k都属于L

我们这样定义一个集合的F值

F(S)=F(S^d)+F(S^d)*qd+d d为集合中最大的一个数 S^d表示S去掉d后的集合

每次给定a,b

要求求出满足被L的第a项A整除且整除L的第b项B的集合的F值

Solution

F({a,b})=qab+a+b

向上面那样多展开几层,就可以得到这样的一个的F的计算公式

然而并无用。。我想到的时候还以为。。。

F(S)=q*F(S^d)*F({d})+F(S^d)

在做的时候,发现所有子集的d的乘积乘上q^(size-1)的和就是答案

好像没有用?

但qF(S)+1有很优美的形式//自行YY。。。

若S=A+B//+在这里表示集合的并

我们发现qF(S)+1=(qF(A)+1)*(qF(B)+1)

得F(S)=qF(A)F(B)+F(A)+F(B)

如果lucky={2}那么显然就是2^(a~b)的连续的一段

询问连续一段的可并信息?Seg走起

至于为什么是2~6,而没有7这个质数就自己想去吧显而易见了

2 3 5三个线段树套一起,那真是。。。

还有一个优化 若无2,3,4 6可以看成一个质数

暴力处理出L的前1e5项,//具体使用priority_queue实现

据说这题可以用一种映射的方式免除插入而在建树的时候统计答案

写的时候,念念不忘template,然后就写成了这个鬼样子

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cctype>
using namespace std;
namespace IO{
    const int ios=1<<17;
    char R[ios],*Rc=R,*RB=R;
    inline int gec(){return(Rc==RB&&(RB=(Rc=R)+fread(R,1,ios,stdin),Rc==RB))?EOF:*Rc++;}
    template<typename Tp>inline int read(Tp&A){
        static int c,sg;c=gec();sg=0;A=0;
        while(!isdigit(c)&&c!=EOF)sg|=(c=='-'),c=gec();
            if(c==EOF)return EOF;
        while(isdigit(c))A=(A<<3)+(A<<1)+(c^'0'),c=gec();
        return A=sg?-A:A,0;
    }
}
using IO::gec;using IO::read;
int P,bitQ,A1,A2,A3;
namespace Seg{
	template<typename Tp>inline void upd(Tp&a,const Tp&b){a=((1LL*a*b)%P*bitQ+a+b)%P;}
	int newValue,res;
	template<typename BT,typename AT,typename QT,typename subtype,const int Trs>struct Seg{
		BT B;AT A;QT Q;
		subtype sub[Trs];
		int lc[Trs],rc[Trs];
		int Lc,Rc,NO,pos;
		void ins(int&i,const int&l,const int&r){
			if(!i)i=++NO,sub[i]=0;
			A(sub[i]);
			if(l<r){
				int mid=(l+r)>>1;
				if(pos<=mid)ins(lc[i],l,mid);
				else ins(rc[i],mid+1,r);
			}
		}
		void bld(int&i,const int&l,const int&r){
			i=++NO;
			B(sub[i]);
			if(l<r){
				int mid=(l+r)>>1;
				bld(lc[i],l,mid);
				bld(rc[i],mid+1,r);
			}
		}
		void Qry(const int&i,const int&l,const int&r){
			if(!i)return;
			if(Lc<=l&&r<=Rc)return Q(sub[i]);
			int mid=(l+r)>>1;
			if(Lc<=mid)Qry(lc[i],l,mid);
			if(Rc>mid)Qry(rc[i],mid+1,r);
		}
	};
	struct B3{void operator()(int&sub)const{sub=0;}};
	struct Q3{void operator()(int sub)const{return upd(res,sub);}};
	struct D3{void operator()(int&sub)const{return upd(sub,newValue);}};
	Seg<B3,D3,Q3,int,10000010>T3;

	struct B2{void operator()(int&sub)const{T3.bld(sub,0,A3);}};
	struct Q2{void operator()(int sub)const{return T3.Qry(sub,0,A3);}};
	struct D2{void operator()(int&sub)const{return T3.ins(sub,0,A3);}};
	Seg<B2,D2,Q2,int,5000010>T2;
		
	struct B1{void operator()(int&sub)const{T2.bld(sub,0,A2);}};
	struct Q1{void operator()(int sub)const{return T2.Qry(sub,0,A2);}};
	struct D1{void operator()(int&sub)const{return T2.ins(sub,0,A2);}};
	Seg<B1,D1,Q1,int,3000010>T1;
}
namespace NumWork{
	const double eps=1e-6;
	struct Num{
		Num(){}
		Num(int a1,int a2,int a3,double ln,long long d):a1(a1),a2(a2),a3(a3),re(ln),val(d%P){}
		int a1,a2,a3,val;
		double re;
		bool operator <(Num A)const{return re>A.re;}
		bool operator ==(Num A)const{return val==A.val&&fabs(re-A.re)<eps;}
		bool judge(Num A)const{return a1<=A.a1&&a2<=A.a2&&a3<=A.a3;}
		Num operator *(Num A){return Num(a1+A.a1,a2+A.a2,a3+A.a3,re+A.re,1ll*val*A.val);};
	};
	priority_queue<Num> HP;
	static const int limit=100000;
	int pr[10],prpr,Counter,OK[10],times[10][10],state,HLJ;
	Num bit[10],que[limit+5];
//	#define read(a) scanf("%d",&a)
	void init(){
		freopen("volunteer.in","r",stdin);
		freopen("volunteer.out","w",stdout);
		for(int id=2;id<=6;id++){
			read(OK[id]);
			state|=(OK[id]<<(id-2));
		}
		if(state==16){
			pr[prpr++]=6;
		}else if(state==24){
			pr[prpr++]=5;pr[prpr++]=6;
		}else{
			if(state&21)pr[prpr++]=2;
			if(state&18)pr[prpr++]=3;
			if(state&8)pr[prpr++]=5;
		}
		read(P);read(bitQ);
	}
	void work(){
		for(int id=2;id<=6;id++){
			if(OK[id]){
				int tmp=id;
				for(int i=0;i<prpr;i++)
					while(tmp%pr[i]==0)tmp/=pr[i],times[id][i]++;		
				HP.push(bit[id]=Num(times[id][0],times[id][1],times[id][2],log(id),id));
			}
		}
		while(Counter<limit){
			Num tmp;
			while(tmp=HP.top(),Counter&&que[Counter]==tmp)
				HP.pop();
			HP.pop();
			que[++Counter]=tmp;
			A1=max(A1,tmp.a1);
			A2=max(A2,tmp.a2);
			A3=max(A3,tmp.a3);
			for(int id=2;id<=6;id++){
				if(OK[id])HP.push(tmp*bit[id]);
			}
		}
		using namespace Seg;
		//T1.bld(HLJ,0,A1);
		for(int i=1;i<=Counter;i++){
			T1.pos=que[i].a1;
			T2.pos=que[i].a2;
			T3.pos=que[i].a3;
			newValue=que[i].val;
			T1.ins(HLJ,0,A1);	
		}
	}
	void solve(){
		using namespace Seg;
		int QwQ,a,b;
		read(QwQ);
		while(QwQ--){
			read(a);read(b);
			Num A=que[a],B=que[b];
			if(!A.judge(B))puts("0");
			else{
				T1.Lc=A.a1,T1.Rc=B.a1;
				T2.Lc=A.a2,T2.Rc=B.a2;
				T3.Lc=A.a3,T3.Rc=B.a3;
				res=0;T1.Qry(HLJ,0,A1);
				printf("%d\n",res);
			}
		}	
	}
}
int main(){
	NumWork::init();
	NumWork::work();
	NumWork::solve();	
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值