记录编号 396207 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [HZOI 2015] Keller与驴蛋蛋与海蜇 最终得分 100
用户昵称 GravatarYGOI_真神名曰驴蛋蛋 是否通过 通过
代码语言 C++ 运行时间 44.871 s
提交时间 2017-04-18 17:38:10 内存使用 20.56 MiB
显示代码纯文本
#include <math.h>
#include <ctime>
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int MAXN=65539;
typedef long long TYPE;
typedef int type;
type mod=119<<23|1;
type god=3;
inline int input()
{
	static int x;
	scanf("%d",&x);
	return x;
}
type pow(type a,type b,type Mod=mod)
{
	type ans=1;
	for(; b; b>>=1,a=(TYPE)a*a%Mod)
		if(b&1)ans=(TYPE)ans*a%Mod;
	return ans;
}
namespace NumberTheory {
	
	#define print(f,g) 					\
	{									\
		printf("Printing "#f"\n");		\
		for(int i=0;i<(g)-(f);++i) {	\
			printf("%d ",(f)[i]);		\
		}printf("\n");					\
	}
	inline void upload(type&a) {a=(a<0?a+mod:a);}
	
	namespace Number_Lock
	{
		int cnt,num[64];
		void Breaker(int N)
		{
			cnt=0;
			for(int i=2; 1ll*i*i<=N; ++i)
			{
				if(N%i==0)
				{
					num[++cnt]=i;
				}
				while(N%i==0)N/=i;
			}
			if(N>1)num[++cnt]=N;
		}
		int getRoot(int N)
		{
			Breaker(N-1);
			for(int j,i=2; i<N; ++i)
			{
				for(j=1; j<=cnt; ++j)
				{
					if(pow(i,(N-1)/num[j],N)==1)break;
					//printf("%d\n",pow(i,(N-1)/num[j],N));
				}
				if(j>cnt)return i;
			}
			return 0;
		}
	}
	int getLen(int L)
	{
		int len=1;
		while(len<L)len<<=1;
		return len;
	}
	type w_init[2][17][MAXN+10];
	int FFT_init()
	{
		const int N=MAXN;
		for(int is=0; is<2; ++is)
			for(int m=2,h=1; m<=N; m<<=1,++h)
			{
				const int mh=m>>1;
				const type wn=pow(god,is==1?(mod-1)-(mod-1)/m:(mod-1)/m);
				for(int r=0; r<N; r+=m)
				{
					type w=1;
					for(int k=0; k<mh; ++k)
					{
						w_init[is][h][r+k]=w;
						w=(TYPE)w*wn%mod;
					}
				}
			}
		return 0;
	}
	void rotate(type *a,int N)
	{
		for(int i=1,j=0; i<N; ++i)
		{
			int k=N;
			do j^=(k>>=1);
			while(j<k);
			if(i<j)std::swap(a[i],a[j]);
		}
	}
	void FFT(type*a,int N,int is)
	{
		static int protect=FFT_init();
		rotate(a,N);
		if(is<0)is=0;
		for(int m=2,h=1; m<=N; m<<=1,++h)
		{
			const int mh=m>>1;
			for(int r=0; r<N; r+=m)
			{
				type*w=w_init[is][h]+r;
				type*b=a+r;
				type*c=a+r+mh;
				for(int k=0; k<mh; ++k)
				{
					const type v=(TYPE)(*c)*(*w)%mod;
					*c=(*b-v);upload(*c);
					*b=(*b-mod+v);upload(*b);
					++b;
					++c;
					++w;
				}
			}
		}
		if(is==0)
		{
			// std::reverse(a,a+N);
			const type inv=pow(N,mod-2,mod);
			for(int i=0; i<N; ++i)
			{
				a[i]=(TYPE)a[i]*inv%mod;
			}
		}
	}
	void getInv(type*a,type*b,int N)
	{
		if(N==1)
		{
			b[0]=pow(a[0],mod-2);
			return ;
		}
		getInv(a,b,N>>1);
		static type c[MAXN];
		const int mh=N<<1;
		memcpy(c,a,sizeof(type)*N);
		memset(c+N,0,sizeof(type)*N);
		FFT(c,mh,1);
		FFT(b,mh,1);
		for(int i=0; i<mh; ++i)
		{
			b[i]=(2ll-(TYPE)c[i]*b[i]%mod)*b[i]%mod;
			upload(b[i]);
		}
		FFT(b,mh,-1);
		memset(b+N,0,sizeof(type)*N);
	}
	void _mul_littler_(const type*_a,const int&la,const type*_b,const int&lb,type*_c)
	{
		static type c[MAXN];
		memset(c,0,sizeof(type)*(la+lb-1));
		for(int i=0; i<la; ++i)
		{
			for(int j=0; j<lb; ++j)
			{
				c[i+j]+=(TYPE)_a[i]*_b[j]%mod-mod;
				c[i+j]%=mod;upload(c[i+j]);
			}
		}
		memcpy(_c,c,sizeof(type)*(la+lb-1));
	}
	void _mul_greater_(const type*_a,const int&_la,const type*_b,const int&_lb,type*_c)
	{
		static type a[MAXN],b[MAXN];
		int la=_la,lb=_lb;
		while(la>1&&_a[la-1]==0)--la;
		while(lb>1&&_b[lb-1]==0)--lb;
		int len=getLen(la+lb);
		memcpy(a,_a,sizeof(type)*la);
		memset(a+la,0,sizeof(type)*(len-la));
		memcpy(b,_b,sizeof(type)*lb);
		memset(b+lb,0,sizeof(type)*(len-lb));
		FFT(a,len,1);
		FFT(b,len,1);
		for(int i=0; i<len; ++i)a[i]=(TYPE)a[i]*b[i]%mod;
		FFT(a,len,-1);
		for(int i=0; i<la+lb-1; ++i)_c[i]=a[i];
	}
	const int COMPLEX=1E3;
	void mulWith(const type*_a,const int&la,const type*_b,const int&lb,type*_c)
	{
		if(1ll*la*lb<COMPLEX)
		{
			_mul_littler_(_a,la,_b,lb,_c);
		}
		else
		{
			_mul_greater_(_a,la,_b,lb,_c);
		}
	}
	void divWith(const type*_a,const int&la,const type*_b,const int&lb,type*_c)
	{
		static type a[MAXN],b[MAXN],c[MAXN];
		int len=getLen(la),lc=la-lb+1;
		memset(c,0,sizeof(type)*len<<1);
		memcpy(a,_a,sizeof(type)*la);
		memset(a+la,0,sizeof(type)*(len-la));
		memcpy(b,_b,sizeof(type)*lb);
		memset(b+lb,0,sizeof(type)*(len-lb));
		std::reverse(a,a+la);
		std::reverse(b,b+lb);
		getInv(b,c,len);
		mulWith(a,la,c,len,c);
		std::reverse(c,c+lc);
		for(int i=0; i<lc; ++i)_c[i]=c[i];
	}
	void modWith(const type*_a,const int&_la,const type*_b,const int&_lb,type*_d)
	{
		static type c[MAXN],lc;
		int la=_la,lb=_lb;
		const int len=getLen(la);
		while(la>1&&_a[la-1]==0)--la;
		while(lb>1&&_b[lb-1]==0)--lb;
		if(lb>la)
		{
			for(int i=0; i<la; ++i)
				_d[i]=_a[i];
			return;
		}
		memset(c,0,sizeof(type)*la);
		lc=la-lb+1;
		divWith(_a,la,_b,lb,c);
		while(lc>1&&c[lc-1]==0)--lc;
		mulWith(_b,lb,c,lc,c);
		for(int i=0; i<la; ++i)
		{
			c[i]=(_a[i]-c[i])%mod;
			upload(c[i]);
		}
		lc=la;
		while(lc>1&&c[lc-1]==0)--lc;
		for(int i=0; i<lc; ++i)_d[i]=c[i];
	}
	type save[MAXN];
	type answer[16][MAXN];
	type filter[16][MAXN];
	type w[MAXN];
	void doubleDivsion(int l,int r,int dep)
	{
		if(l==r+1)return;
		if(r==l+2)
		{
			save[l>>1]=answer[dep][l];
			return;
		}
		int m=(l+r)>>1,nex=dep+1;
		modWith(answer[dep]+l,r-l,filter[nex]+l,m-l,answer[nex]+l);
		modWith(answer[dep]+l,r-l,filter[nex]+m,r-m,answer[nex]+m);
		doubleDivsion(l,m,nex);
		doubleDivsion(m,r,nex);
	}
	void doubleUnion(int l,int r,int dep)
	{
		if(r==l+1) return;
		int m=((l+r)>>1),nex=dep+1;;
		doubleUnion(l,m,nex);
		doubleUnion(m,r,nex);
		if(r==l+2)
		{
			if(w[l]!=-1)
			{
				filter[dep][l]=w[l];
				filter[dep][l+1]=1;
			}
			else
			{
				filter[dep][l]=1;
				filter[dep][l+1]=0;
			}
		}
		else mulWith(filter[nex]+l,m-l,filter[nex]+m,r-m,filter[dep]+l);
	}
	void causeLight(type*f,int N)
	{
		memset(w,-1,sizeof(w));
		memset(filter,0,sizeof(filter));
		int len=getLen(N)<<1;
		for(int i=0; i<N; ++i)w[i<<1]=f[i];
		doubleUnion(0,len,0);
	}
	void insite(type*a,int N,type*f)
	{
		static type g[MAXN];
		int len=getLen(N)<<1;
		memset(g,0,sizeof(type)*len);
		for(int i=0; i<N; ++i)g[i]=f[i];
		causeLight(g,N);
		modWith(a,len,filter[0],len,answer[0]);
		doubleDivsion(0,len,0);
	}
	int runHigh(int N)
	{
		type ans=1;
		for(int i=1; i<=N; ++i)
		{
			ans=1ll*ans*i%mod;
		}
		if(N&1)ans=1ll*ans*pow(2,mod-2,mod)%mod;
		printf("%lld\n",ans);
		return 0;
	}
	type c[MAXN],e[MAXN],B;
	int Exceed(int N,int Mod)
	{
		B=sqrt(N);
		mod=Mod;
		god=Number_Lock::getRoot(mod);
		for(int i=0; i<B; ++i)
		{
			c[i]=i+1;
		}
		causeLight(c,B);
		memcpy(e,filter[0],sizeof(type)*B<<1);
		for(int i=0; i<B; ++i)
		{
			c[i]=(mod-(TYPE)i*B%mod)%mod;
		}
		insite(e,B,c);
		return 0;
	}
	int Fraction(int N) {
		int n=N/B*B,ans=1;
		
		for(int i=0;i<n;i+=B)
		{ans=(TYPE)ans*save[i/B]%mod;}
		for(int i=n+1;i<=N;++i)
		{ans=(TYPE)ans*i%mod;}//printf("%d %d\n",B,ans);
		return ans;
	}
}
int js[MAXN],ij[MAXN];
void PreJS(const int N=MAXN-2) {
	js[0]=1;
	for(int i=1;i<=N;++i) {
		js[i]=(TYPE)js[i-1]*i%mod;
	}ij[N]=pow(js[N],mod-2,mod);
	for(int i=N-1;i>=0;--i) {
		ij[i]=(TYPE)ij[i+1]*(i+1)%mod;
	}//printf("%d\n",js[65534]);
	for(int i=1;i<=N;++i) {
		js[i]=(TYPE)js[i-1]*js[i]%mod;
		ij[i]=(TYPE)ij[i-1]*ij[i]%mod;
	}
}
int main() {
	freopen("seaHibernate.in","r",stdin);
	freopen("seaHibernate.out","w",stdout);
	NumberTheory::Exceed(9E8+10,input());PreJS();
	int Q=input();
	for(int i=1;i<=Q;++i) {
		int k=input();
		int n=input();
		int f=NumberTheory::Fraction(n*k);
		int a=(TYPE)js[n+k-1]*ij[n-1]%mod;
		int b=(TYPE)js[k-1];
		//printf("%d %d %d\n",f,a,b);
		//fprintf(stderr,"case :%d\n",i);
		printf("%lld\n",(TYPE)f*b%mod*pow(a,mod-2,mod)%mod);
	}fclose(stdin);fclose(stdout);
	return 0;
}