【CF1025G】Company Acquisitions(势能函数)
- 有\(n\)个点,其中有一部分关键点,关键点不跟随其他点,非关键点必然跟随某个关键点。
- 每个回合随机选择两个关键点\(x,y\),让\(x\)变成跟随\(y\)的非关键点,并把原本跟随\(x\)的所有点设为关键点。
- 求期望多少回合后只剩一个关键点。
- \(n\le500\)
势能函数
非常玄学的一个科技。
对于一类特殊的期望问题,我们试图构造一个函数来评估某一个局面,满足任意局面在一次操作后的期望函数值都恰好增加\(1\),那么答案就是最终局面的函数值减去初始局面的函数值了。这种函数被称作势能函数。
对于这道题,对于一个局面只需要知道跟随每个关键点的非关键点个数\(a_{1\sim m}\),因此不妨设一个局面的势能函数\(F(a_{1\sim m})=\sum_{i=1}^mf(a_i)\)。
由于操作随机,不妨直接考虑只有两个数\(x,y\)时的情况,列出方程:
\[\frac12(f(x+1)+yf(0)+f(y+1)+xf(0))-(f(x)+f(y))=1
\]
不妨令\(f(0)=0\),于是得到:
\[\frac12(f(x+1)+f(y+1))-(f(x)+f(y))=1\\
(\frac12f(x+1)-f(x)-\frac12)+(\frac12f(y+1)-f(y)-\frac12)=0
\]
由于上式对于任意\(x,y\)都成立,所以我们可以分别考虑\(x,y\),得到:
\[\frac12f(x+1)-f(x)-\frac12=0\\
f(x+1)=2f(x)+1
\]
结合\(f(0)=0\),发现\(f(x)=2^x-1\)。
这样一来就可以轻松算出初始局面和最终局面的势能函数值计算答案了。
代码:\(O(n)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 500
#define X 1000000007
using namespace std;
int n,a[N+5],p[N+5];
int main()
{
RI i;for(scanf("%d",&n),i=1;i<=n;++i) p[i]=1;for(i=1;i<=n;++i) scanf("%d",a+i),~a[i]&&(p[a[i]]=2LL*p[a[i]]%X);//每个关键点记录2^x
RI t=1;for(i=1;i^n;++i) t=2LL*t%X;for(--t,i=1;i<=n;++i) !~a[i]&&(t=(t-(p[i]-1)+X)%X);return printf("%d\n",t),0;//最终局面-初始局面
}
待到再迷茫时回头望,所有脚印会发出光芒