IOI2021集训队作业 146BJ Tile Cutting
题意(简化):对于每个\(S\)统计满足\(S=ax+by\)的不同的四元组\((a,x,b,y)\)的个数。
\(S\le 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\n",x,g[x]);
}
return 0;
}