IOI2021集训队作业 146BJ Tile Cutting

题意(简化):对于每个(S)统计满足(S=ax+by)的不同的四元组((a,x,b,y))的个数。

(Sle 5*10^5)


统计每个数的因数。设其生成函数为(F),则答案为(F^2)

经过估算和打表发现答案没有超过(998244353),放心NTT。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#include <cmath>
#define N 500000
#define ll long long
#define mo 998244353
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
ll f[N+5],g[N+5];
#define nN 1048576
int re[nN];
void dft(ll A[],int flag){
	for (int i=0;i<nN;++i)
		if (i<re[i])
			swap(A[i],A[re[i]]);
	static ll wnk[nN];
	for (int i=1;i<nN;i<<=1){
		ll wn=qpow(3,flag==1?(mo-1)/(2*i):mo-1-(mo-1)/(2*i));
		wnk[0]=1;
		for (int k=1;k<i;++k)
			wnk[k]=wnk[k-1]*wn%mo;
		for (int j=0;j<nN;j+=i<<1)
			for (int k=0;k<i;++k){
				ll x=A[j+k],y=A[j+k+i]*wnk[k];
				A[j+k]=(x+y)%mo;
				A[j+k+i]=(x-y)%mo;
			}
	}
	for (int i=0;i<nN;++i)
		A[i]=(A[i]+mo)%mo;
	if (flag==-1){
		ll invn=qpow(nN);
		for (int i=0;i<nN;++i)
			A[i]=A[i]*invn%mo;
	}
}
void multi(ll g[],ll f[]){
	for (int i=1;i<nN;++i)
		re[i]=re[i>>1]>>1|(i&1)<<20-1;
	static ll A[nN];
	for (int i=1;i<=N;++i)
		A[i]=f[i];
	dft(A,1);
	for (int i=0;i<nN;++i)
		A[i]=A[i]*A[i]%mo;
	dft(A,-1);
	for (int i=1;i<=N;++i)
		g[i]=A[i];
}
int h[19][N];
int gmax(int x,int y){return g[x]>g[y]?x:y;}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("right.txt","w",stdout);
	for (int i=1;i<=N;++i)
		for (int j=i;j<=N;j+=i)
			f[j]++;
	multi(g,f);
	for (int j=1;j<=N;++j)
		h[0][j]=j;
	for (int i=1;i<19;++i)
		for (int j=1;j+(1<<i)-1<=N;++j)
			h[i][j]=gmax(h[i-1][j],h[i-1][j+(1<<i-1)]);
	int Q;
	scanf("%d",&Q);
	while (Q--){
		int l,r;
		scanf("%d%d",&l,&r);
		int m=log2(r-l+1);
		int x=gmax(h[m][l],h[m][r-(1<<m)+1]);
		printf("%d %lld
",x,g[x]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/13854291.html