P6913 [ICPC2015 WF]Tile Cutting

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;
}
原文地址:https://www.cnblogs.com/zzctommy/p/13985317.html