1. 程式人生 > 其它 >CF653G Move by Prime 題解

CF653G Move by Prime 題解

Codeforces
Luogu

Description.

定義 \(F(S)\) 為把 \(S\) 中每次可以把每個元素 \(\times p,\div p(p\in\text{prime})\) 把所有元素變相同的最少步數。
\(\sum_{T\subseteq S}F(T)\)

Solution.

質因數可以拆開,分別求解
對於每個質因數,有一個序列表示指數
現在相當於對所有子序列求到中位數差之和
可以考慮列舉中位數為 \(m\)(定義中位數偏左
然後相當於要求 \(\sum|X-m|\) 其中 \(m\) 是中位數。
絕對值拆開後,\(m\) 的貢獻肯定是 \(0\)
相當於在左邊選 \(a\)

個,右邊選 \(b\) 個的貢獻是下式:

\[\begin{cases} -X&a<b\\ 0&a=b\\ X&a>b\\ \end{cases} \]

可以列舉 \(b-a+i-1\),意義是左邊不選個數和右邊選個數之和。
因為 \(i\) 當前確定,左邊不選、右邊選總方案數就相當於從 \(n-1\) 裡選出這些數,方案數是 \(\dbinom{n-1}{b-a+i-1}\)
則有貢獻為

\[\begin{aligned} &=X\left(\sum_{j=0}^{i-2}\dbinom{n-1}{j}-\sum_{j=i}^{n-1}\dbinom{n-1}{j}\right)\\ &=X\left(2^{n-1}-2\sum_{j=i-1}^{n-1}\dbinom{n-1}{j}+\dbinom{n-1}{i}\right)\\ \end{aligned} \]

然後預處理組合數字首和就做完了。

Coding.

點選檢視程式碼
//Coded by Kamiyama_Shiki on 2021.11.14 {{{
//是啊……你就是那隻鬼了……所以被你碰到以後,就輪到我變成鬼了
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=300005,P=1000000007;
namespace Binom//{{{
{
	int fc[N],fi[N],iv[N];//dbinit
	inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
	inline void dbinit(int n=N-1)
	{
		fc[0]=1;for(int i=1;i<=n;i++) fc[i]=1ll*fc[i-1]*i%P;
		iv[1]=1;for(int i=2;i<=n;i++) iv[i]=1ll*iv[P%i]*(P-P/i)%P;
		fi[0]=1;for(int i=1;i<=n;i++) fi[i]=1ll*fi[i-1]*iv[i]%P;
	}
	inline int C(int n,int m) {return n<0||m<0||n<m?0:1ll*fc[n]*fi[m]%P*fi[n-m]%P;}
}using Binom::dbinit;using Binom::C;using Binom::ksm;//}}}
const int V=N;int pr[V],pc,ls[V];char pv[V];//prinit{{{
inline void prinit(int n=V-1)
{
	pv[1]=1,ls[1]=0;for(int i=1;i<=n;i++)
	{
		if(!pv[i]) pr[++pc]=i,ls[i]=i;
		for(int j=1;j<=pc&&i*pr[j]<=n;j++) {pv[i*pr[j]]=1,ls[i*pr[j]]=pr[j];if(i%pr[j]==0) break;}
	}
}//}}}
int n,a[N],c[N],qz[N],rs=0;vector<int>fc[N];
int main()
{
	read(n),prinit(),dbinit();for(int i=1;i<=n;i++) read(a[i]);
	int pw=ksm(2,n-1);for(int i=n-1;~i;i--) qz[i]=(qz[i+1]+(c[i]=C(n-1,i)))%P;
	for(int i=1,x=a[i];i<=n;x=a[++i]) while(ls[x]) {int v=ls[x],c=0;while(x%v==0) x/=v,c++;fc[v].push_back(c);}
	for(int i=1;i<N;i++) if(!fc[i].empty())
	{
		sort(fc[i].begin(),fc[i].end());int cnt=n-fc[i].size();
		//printf("%d\n",i);for(int j:fc[i]) printf("%d ",j);putchar('\n');
		for(int j=0;j<(int)fc[i].size();j++) rs=(rs+1ll*fc[i][j]*(pw-2ll*qz[cnt+j]%P+P+c[cnt+j]))%P;
		//for(int j=0;j<(int)fc[i].size();j++) printf("gg %d - %lld + %d\n",pw,2ll*qz[cnt+j]%P,c[cnt+j]);
	}return printf("%d\n",rs),0;
}