[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;
}
posted @ 2021-02-24 12:32  zkdxl  阅读(60)  评论(0编辑  收藏  举报