[CF1025G] Company Acquisitions
\(\text{Problem}:\)题目链接
\(\text{Solution}:\)
非常巧妙的一道全局思维题。与 CF1375G 有着异曲同工之妙。
此处引入一种势能函数。设当前状态为 \(S\),存在一个函数 \(F(S)\),使得每次操作可以使得 \(F(S)\) 的期望增加 \(1\),那么 \(F(目标状态)-F(初始状态)\) 就是答案。同时,势能函数的定义需要满足目标状态在定义内无法转移(如果存在环,将会难以定义势能)。
设 \(F(S)=\sum\limits_{a_{i} \in S} g(a_{i})\),\(g(x)\) 表示有 \(x\) 个点跟着这个点,且这个点不跟着其他点,那么一次操作有如下转移方程:
\(g(x)+g(y)+1=\cfrac{1}{2}[g(x+1)+y\times g(0)]+\cfrac{1}{2}[x\times g(0)+g(y+1)]\)
在势能函数中,我们钦定 \(g(0)=0\),得到:
\(g(x)+g(y)+1=\cfrac{1}{2}[g(x+1)+g(y+1)]\)
\(g(x+1)+g(y+1)=2g(x)+1+2g(y)+1\)
到了这一步,不难发现 \(g(x)=2^{x}-1\)。于是可以直接计算。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=510, Mod=1e9+7;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,a[N];
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=x*x%Mod) if(p&1) res=res*x%Mod; return res; }
signed main()
{
n=read();
for(ri int i=1;i<=n;i++)
{
int x=read();
if(~x) a[x]++;
}
int Ans=0;
for(ri int i=1;i<=n;i++)
{
Ans=(Ans+ksc(2,a[i])-1+Mod)%Mod;
}
printf("%lld\n",(ksc(2,n-1)-1-Ans+Mod+Mod)%Mod);
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。