P6913 [ICPC2015 WF]Tile Cutting
我居然只会打NTT就做出WF的多项式题了。会做这些题有什么用哦,CSP又发挥不出来/ll
变量标在图上了,有4个,设平行四边形的面积为 (w)
那么
[w=xy-ab-(x-a)(y-b)\
xy-ab-xy+ay+xb-ab=w\
ay+xb-2ab=w\
a(y-b)+b(x-a)=w\
alphaeta+gamma heta=w\
]
最后一步可以直接替换,并不需要多余的限制条件。
因为 (a,b) 均与 (x,y) 无关,所以 (x-a,y-b) 的大小均任意。
令 (g_i) 表示 (xy=i) 的 ((x,y)) 个数。
那么 (f(w)=sum_{i=1}^{w-1}g_i*g_{w-i}) 直接卷积就好了。
(g_i) 直接筛就是 (O(nln n)) ,线性筛因子个数也行,只是没必要,这里的常数和 (NTT) 比小到哪里去都不知道了。
答案上界是要估算一下的。
(g_i) 最大是 (200) ,那么 (g_ig_jle 40000) ,那么 (f(w)le 40000*500000=2e10) ,事实上大部分 (g_i) 远达不到 (200) ,毛估估 炸不掉 (998244353) ,拿NTT卷即可。
实测最大 160474864
至于要求区间最大值,随你怎么求了。
居然和El跑的一样快?!我和Eltietie
为啥yhx跑的那么快啊,被吊打了/ll
这道题的通过率在我做完之后居然还是100%,不可思议。
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
typedef long long LL;
typedef double db;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
#define N 500005
#define M (N<<2)
#define C 500000
#define mod 998244353
int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
int a[M],rev[M],lg,lim;
int id[20][N],mx[20][N],lg2[N],pw2[40];
int n;
void init_poly(int n){
for(lim=1,lg=0;lim<n;lim<<=1,++lg);
for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
}
void fmod(int&x){x-=mod,x+=x>>31&mod;}
void NTT(int*a,int g,int op=0){
for(int i=0;i<lim;++i)
if(i>rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<lim;i<<=1){
int wn=qpow(g,(mod-1)/(i<<1));
for(int j=0;j<lim;j+=i<<1){
int w0=1;
for(int k=0;k<i;++k,w0=1ll*w0*wn%mod){
int X=a[j+k],Y=1ll*w0*a[i+j+k]%mod;
a[j+k]=(X+Y)%mod,a[i+j+k]=(X-Y+mod)%mod;
}
}
}
if(!op)return;int ilim=qpow(lim,mod-2);
for(int i=0;i<lim;++i)a[i]=1ll*a[i]*ilim%mod;
}
void init_ST(const int&n){
lg2[0]=-1;for(int i=1;i<=n;++i)lg2[i]=lg2[i>>1]+1;
pw2[0]=1;for(int i=1;i<=20;++i)pw2[i]=pw2[i-1]<<1;
for(int i=1;i<=n;++i)mx[0][i]=a[i],id[0][i]=i;
for(int i=1;i<=lg2[n];++i)
for(int j=1;j+pw2[i]-1<=n;++j){
int t=j+pw2[i-1];
if(mx[i-1][j]>=mx[i-1][t])mx[i][j]=mx[i-1][j],id[i][j]=id[i-1][j];
else mx[i][j]=mx[i-1][t],id[i][j]=id[i-1][t];
}
}
void ask(int l,int r){
int x=lg2[r-l+1],t=r-pw2[x]+1;
if(mx[x][l]>=mx[x][t])printf("%d %d
",id[x][l],mx[x][l]);
else printf("%d %d
",id[x][t],mx[x][t]);
}
signed main(){
for(int i=1;i<=C;++i)
for(int j=1;i*j<=C;++j)
++a[i*j];
init_poly(C<<1),NTT(a,3);
for(int i=0;i<lim;++i)a[i]=1ll*a[i]*a[i]%mod;
NTT(a,qpow(3,mod-2),1);
init_ST(C);
n=read();
while(n--){
int l=read(),r=read();
ask(l,r);
}
return 0;
}