AT_arc114_c

提供一个更臭一点的 O(n)O(n) 做法。

首先分析,如果现在已知 AA,怎么求 f(A)f(A)。首先贪心地想,设依次操作 viv_i,若 vi+1<viv_{i+1}<v_i,那么换成先操作 viv_ivi+1v_{i+1} 一定不劣,因为可能的结果后者包含前者。于是一定是按 vv 从小到大操作。

然后发现,对于一个 ai=aj=xa_i=a_j=x,若 k(i,j),ak<x\exists k\in(i,j),a_k<x,则无法用一次操作同时使 ai,aja_i,a_j 满足要求,否则会影响中间已经确定的数。同时,若 aia_i 这个数是第一次出现,显然也要一次操作。

然后拆开算贡献。对于第一种情况,考虑枚举 ai=ka_i=k 上一次出现的位置为 jj,则 (i,j,k)(i,j,k) 产生贡献的要求有:(i,j)(i,j) 中没有 kkp(i,j),ap<k\exists p\in(i,j),a_p<k。计算方案数,考虑算没有 kk 的方案减去全 >k>k 的方案,为 ((m1)ij1(mk)ij1)mni+j1((m-1)^{i-j-1}-(m-k)^{i-j-1})m^{n-i+j-1},后面的 mm 是其他位置任取的方案数。于是方案数为:

i=1nk=1mj=1i1((m1)ij1(mk)ij1)m(n(ij+1))\sum\limits_{i=1}^n\sum\limits_{k=1}^m\sum\limits_{j=1}^{i-1}((m-1)^{i-j-1}-(m-k)^{i-j-1})m^{(n-(i-j+1))}

然后推式子。发现只和 iji-j 有关:

=i=1n1k=1m((m1)i1(mk)i1)(ni)mni1=\sum\limits_{i=1}^{n-1}\sum\limits_{k=1}^m((m-1)^{i-1}-(m-k)^{i-1})(n-i)m^{n-i-1}

改变枚举顺序。

=k=1mi=1n1((m1)i1(ni)mni1(mk)i1(ni)mni1)=\sum\limits_{k=1}^m\sum\limits_{i=1}^{n-1}((m-1)^{i-1}(n-i)m^{n-i-1}-(m-k)^{i-1}(n-i)m^{n-i-1})

对于 xiynix^iy^{n-i} 状物,有个 trick 是提出来 yny^n 变成 yn(xy)iy^n(\frac xy)^i

=mn2k=1mi=1n1((m1m)i1(ni)(mkm)i1(ni))=m^{n-2}\sum\limits_{k=1}^m\sum\limits_{i=1}^{n-1}((\frac{m-1}{m})^{i-1}(n-i)-(\frac{m-k}{m})^{i-1}(n-i))

=mn2(nk=1mi=1n1((m1m)i1(mkm)i1)k=1mi=1n1(i(m1m)i1i(mkm)i1))=m^{n-2}(n\sum\limits_{k=1}^m\sum\limits_{i=1}^{n-1}((\frac{m-1}{m})^{i-1}-(\frac{m-k}{m})^{i-1})-\sum\limits_{k=1}^m\sum\limits_{i=1}^{n-1}(i(\frac{m-1}{m})^{i-1}-i(\frac{m-k}{m})^{i-1}))

发现前半部分是等比数列形式,可以 O(1)O(1) 算。后半形似 (i+1)xi\sum (i+1)x^i,对于这种的处理,令 A=i=0n(i+1)xi,xA=i=1n+1ixiA=\sum\limits_{i=0}^n (i+1)x^i,xA=\sum\limits_{i=1}^{n+1} ix^i,相减得 (x1)A=(n+1)xn+1i=0nxi(x-1)A=(n+1)x^{n+1}-\sum\limits_{i=0}^nx^i,结合等比数列也是 O(1)O(1)

于是 令 f(x,n)=i=0nxi=xn+11x1,g(x,n)=i=0n(i+1)xi=(n+1)xn+1f(x,n)x1f(x,n)=\sum\limits_{i=0}^nx^i=\frac{x^{n+1}-1}{x-1},g(x,n)=\sum\limits_{i=0}^{n}(i+1)x^i=\frac{(n+1)x^{n+1}-f(x,n)}{x-1},则有:

=mn2(nk=1m(f(m1m,n2)f(mkm,n2))k=1m(g(m1m,n2)g(mkm,m2)))=m^{n-2}(n\sum\limits_{k=1}^m(f(\frac{m-1}{m},n-2)-f(\frac{m-k}{m},n-2))-\sum\limits_{k=1}^m(g(\frac{m-1}{m},n-2)-g(\frac{m-k}{m},m-2)))

此时 O(nlogn)O(n\log n) 已经是简单的,至于 O(n)O(n),容易发现需要快速幂的只有 xn1x^{n-1},线性筛预处理,再预处理一些逆元即可。

后面部分的式子比较简单,为 i=1nk=1m(m1)i1mni\sum\limits_{i=1}^n\sum\limits_{k=1}^m(m-1)^{i-1}m^{n-i}。容易发现与 kk 无关,于是动态维护后面两个东西即可。

code:

int n,m,s,pm[N],pw[N],inv[N];
int ivm,ivmp;
bool vis[N];
il int Mod(int x,int y){
	return x+y>=mod?x+y-mod:x+y;
}
il int qpow(int x,int y){
	int ret=1;
	while(y){
		if(y&1){
			ret=1ll*ret*x%mod;
		}
		x=1ll*x*x%mod,y>>=1;
	}
	return ret;
}
il int F(int x){
	return mod-1ll*Mod(1ll*pw[x]*ivmp%mod,mod-1)*m%mod*inv[m-x]%mod;
}
il int G(int x){
	return mod-1ll*Mod(1ll*(n-1)*pw[x]%mod*ivmp%mod,mod-F(x))*m%mod*inv[m-x]%mod;
}
void Yorushika(){
	read(n,m);
	if(n==1){
		printf("%d\n",m);
		return;
	}
	pw[1]=inv[1]=1;
	rep(i,2,m){
		inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		if(!vis[i]){
			pm[++s]=i;
			pw[i]=qpow(i,n-1);
		}
		rep(j,1,s){
			if(pm[j]>m/i){
				break;
			}
			vis[i*pm[j]]=1;
			pw[i*pm[j]]=1ll*pw[i]*pw[pm[j]]%mod;
			if(i%pm[j]==0){
				break;
			}
		}
	}
	ivm=qpow(m,mod-2),ivmp=qpow(ivm,n-1);
	int ans=0;
	rep(k,1,m){
		ans=Mod(ans,1ll*n*Mod(F(m-1),mod-F(m-k))%mod);
		ans=Mod(ans,mod-Mod(G(m-1),mod-G(m-k)));
	}
	ans=1ll*ans*qpow(m,n-2)%mod;
	int x=1,y=qpow(m,n-1);
	rep(i,1,n){
		ans=Mod(ans,1ll*x*y%mod*m%mod);
		x=1ll*x*(m-1)%mod,y=1ll*y*inv[m]%mod;
	}
	printf("%d\n",ans);
}
signed main(){
	int t=1;
	//read(t);
	while(t--){
		Yorushika();
	}
}

吐槽一下,这种题明明可以出到 n=107n=10^7 结果偏偏出了 n=5000n=5000,直接变成了zz题了……