题解 CF822D 【My pretty girl Noora】

囧仙

2020-05-14 20:26:44

Solution

## 题目大意 $n$个女生,进行若干论选美。选美的方式如下: - 设当前人数为$m$,选择一个正整数$x(m\ge x>1, x\ |\ m)$,划分为$\frac{m}{x}$组,每组$x$个人。 - 每一组中的女生两两比较,共进行$\frac{x\times(x-1)}{2}$次比较。最终每一组只会有$1$名女生晋级。 - 所有晋级的女生继续进行选美,直到只剩下一名女生。 设初始为$n$名女生时最少的**总比较次数**为$f(n)$,求$\sum_{i=l}^r t^{i-l}\times f(i) \mod (10^9+7)$。 ## 题解 根据最终需要我们计算的式子,显然需要求出$x\in [l,r]$时**所有**的$f(x)$。不过$f(x)$比较复杂,让我们先证明几个结论。 ### $0.$简单的化简 设总共$m$人,$x$个人分为一组,则一共需要比较$\frac{m}{x}\times \frac{x\times (x-1)}{2}=\frac{m\times (x-1)}{2}$。 这步化简主要是为了方便下面的推算,并没有什么难度。 ### $1.$每次分组的人数按照从小到大排列 假设目前有$m$轮。进行两次选美,分别是$a$个人一组、$b$个人一组。$(a\ge b>1)$ 先$a$后$b$,总比较次数为: $$\frac{m\times (a-1)}{2}+\frac{m\times (b-1)}{2\times a} \kern{50pt} \cdots \cdots (1) \kern{-50pt}$$ 先$b$后$a$,总比较次数为: $$\frac{m\times (b-1)}{2}+\frac{m\times (a-1)}{2\times b}\kern{50pt} \cdots \cdots (2) \kern{-50pt}$$ 两式相减,得到: $$\begin{aligned}(1)-(2)&=\frac{m}{2\times a\times b}\times(a^2\times b-a\times b+b^2-b+a\times b^2+a\times b-a^2+a)\cr&=\frac{m}{2\times a\times b}\times [a\times b\times (a-b)-(a+b)\times (a-b)+(a-b)]\cr&=\frac{m}{2\times a\times b}\times (a-b)\times (a\times b-a-b+1)\cr&=\frac{m}{2\times a\times b}\times (a-b)\times (a-1)\times (b-1)\end{aligned}$$ 所以$(1)\ge(2)$,因而$a<b$时才能使得总比较次数最少。 ### $2.$如果$x$为合数,就拆分为若干轮选美 不妨设$x=a\times b\ (1< b\le a <x)$,当前人数为$m$。 由结论$1$可以得到,先$b$后$a$比先$a$后$b$更好。再我们考虑每组$a\times b$个人的情况。 每组$a\times b$个人需要的比较次数: $$\frac{m\times (a\times b-1)}{2} \kern{50pt} \cdots \cdots (3) \kern{-50pt}$$ 与先$b$后$a$的情况相减: $$\begin{aligned}(3)-(2)&=\frac{m}{2\times b}\times (a\times b^2-b-b^2+b-a+1)\cr &=\frac{m}{2\times b}\times[(a-1)\times b^2-(a-1)]\cr &=\frac{m}{2\times b}\times (a-1)\times (b+1)\times (b-1)\end{aligned}$$ 因此,$(3)>(2)$,也就是说,拆成两组总是更优。 --- 在证明完上述结论后,我们能得到一个初步的算法: 设$x=\prod_{i=1}^k p_i$,其中$p_i$为质数。那么依次化为$p_1,p_2,\cdots,p_k$个人为一组,可以使得最终的比较次数最少。 考虑区间筛素数的思想。即用$1\sim \sqrt{R}$内的所有质数,筛一遍$[L,R]$内的数字,并统计答案。具体来说,我们用$A_i$表示$f(i)$的贡献,$B_i$表示数字$i$目前还剩下多少。每次用$p$筛一遍含有因子$p$的数字,更新答案($A_i\gets A_i+\frac{B_i\times (p-1)}{2},B_i\gets \frac{B_i}{p}$)。需要注意的是,每个数字可能有若干个质因子$p$,因此需要使用$p^2,p^3\cdots$继续处理。最后$B_i$剩下的要么是$1$,要么是它最大的质因数。处理一遍即可。 最后统计答案就可以了。时间复杂度与埃氏筛法相似,约为$\mathcal O(N \log \log N)$。 另外这里提供一个偷懒的小技巧:由于我们每次要访问$A_{l..r}$,而数组下标从$0$开始非常不方便。于是我们用指针$ * P$指向$A_0-l$,那么访问$P_x$就相当于访问了$A_{x-l}$。因为指针只表示地址,因此不会产生数组越界等问题。 ## 参考代码 ``` #include<bits/stdc++.h> #define up(l,r,i) for(int i=l;i<=r;i++) #define dn(l,r,i) for(int i=l;i>=r;i--) using namespace std; typedef long long LL; const int INF =2147483647; int qread(){ int w=1,c,ret; while((c=getchar())> '9'||c< '0') w=(c=='-'?-1:1); ret=c-'0'; while((c=getchar())>='0'&&c<='9') ret=ret*10+c-'0'; return ret*w; } const int MAXN =5e6+3,MAXM=5e5+3,MOD=1e9+7; int t,l,r,m,M1[MAXN],M2[MAXN],*A,*B,x=1,ans; bool V[MAXM]; int P[MAXM],n; int main(){ t=qread(),l=qread(),r=qread(); A=M1-l,B=M2-l,m=sqrt(r)+1; up(2,m,i){ if(V[i]) continue; P[++n]=i; up(2,m/i,j) V[i*j]=true; } up(l,r,i) B[i]=i; up(1,n,i){ LL p=P[i]; while(p<=r){ int a=(l-1)/p+1,b=r/p; up(a,b,j) A[p*j]=((LL)A[p*j]+(LL)B[p*j]*(P[i]-1)/2)%MOD,B[p*j]/=P[i]; p*=P[i]; } } up(l,r,i) A[i]=((LL)A[i]+(LL)B[i]*(B[i]-1)/2)%MOD; up(l,r,i) ans=((LL)ans+(LL)x*A[i])%MOD,x=((LL)x*t)%MOD; printf("%d\n",ans); return 0; } ```