题解:UVA1718 Tile Cutting
reinforest · · 题解
咋没有人写倍增的 FFT?
令
先预处理出
这个平行四边形的面积就是
因此答案就是对
先对
发现
然后就是静态 RMQ 问题,这个可以使用 ST 表解决。
时间复杂度
#include<bits/stdc++.h>
#define ll long long
#define db long double
using namespace std;
constexpr db eps=1e-8,pi=3.14159265358979323846;
constexpr ll R=5e5+5,maxn=2e6+10;
struct compx{
db x,y;
}f[maxn];
compx operator +(compx a,compx b){
return (compx){a.x+b.x,a.y+b.y};
}
compx operator -(compx a,compx b){
return (compx){a.x-b.x,a.y-b.y};
}
compx operator *(compx a,compx b){
return (compx){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}
ll r[maxn],c[maxn],n,dp[maxn][22],ans[maxn];
void FFT(compx *a,ll lim,ll opt){
for(int i=0;i<lim;i++){
if(i<r[i])swap(a[i],a[r[i]]);
}
for(int len=1;len<lim;len<<=1){
compx mul={1,0},w={cos(pi/len),opt*sin(pi/len)};
for(int i=0;i<lim;i+=(len<<1)){
mul={1,0};
for(int j=0;j<len;j++){
compx a0=a[i+j],a1=mul*a[i+j+len];
a[i+j]=a0+a1;
a[i+j+len]=a0-a1;
mul=mul*w;
}
}
}
if(opt==-1){
for(int i=0;i<lim;i++){
a[i].x=(a[i].x/lim);
}
}
}
void mul(compx *a,ll len){
ll lim=1,L=0;
while(lim<=len+len){
lim<<=1;
L++;
}
for(int i=0;i<lim;i++){
r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
}
FFT(a,lim,1);
for(int i=0;i<lim;i++)a[i]=a[i]*a[i];
FFT(a,lim,-1);
}
ll maxnum(ll a,ll b){
return (ans[a]>=ans[b])?a:b;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
for(int i=1;i<=R;i++){
for(int j=i;j<=R;j+=i){
c[j]++;
}
}
for(int i=1;i<=R;i++){
f[i]={1.0*c[i],0};
}
mul(f,R);
for(int i=1;i<=R;i++){
ans[i]=(ll)(f[i].x+0.5);
dp[i][0]=i;
}
for(int j=1;j<22;j++){
for(int i=1;i+(1<<(j-1))<=R;i++){
//dp[i][j] 表示从 i 开始到 i+2^{j}-1 结束的最大下标
dp[i][j]=maxnum(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
cin>>n;
while(n--){
ll x,y;cin>>x>>y;
ll k=__lg(y-x+1);
ll cur=maxnum(dp[x][k],dp[y-(1<<k)+1][k]);
cout<<cur<<" "<<ans[cur]<<"\n";
}
return 0;
}