[CSP-S模拟测试]:小盆友的游戏(数学 or 找规律)

题目传送门(内部题110)


输入格式

  第一行一个整数$N$,表示小盆友的个数。
  第二行$N$个整数$A_i$,如果$A_i=-1$表示$i$目前是自由身,否则$i$是$A_i$的跟班。


输出格式

  一个整数$X$,表示在模$10^9+7$的情况下,期望总猜拳次数。


样例

样例输入1:

2
-1 -1

样例输出1:

1

样例输入2:

3
-1 -1 -1

样例输出2:

3

样例输入3:

4
-1 -1 -1 -1

样例输出3:

7

样例输入4:

5
-1 -1 -1 -1 -1

样例输出4:

15

样例输入5:

3
-1 -1 2

样例输出5:

2

样例输入6:

4
-1 -1 2 2

样例输出6:

4


数据范围与提示

样例$1$解释:

  无论谁输谁赢,一次猜拳后,一个人就成为另外一个人的跟班,那另外一个人则胜出,游戏结束。

数据范围:

  对于$10\%$的数据,满足$n=1$。
  对于$50\%$的数据,满足$nleqslant 1,000,A_i=-1$。
  对于$100\%$的数据,满足$nleqslant 100,000$。


题解

样例给这么多,而且还是第一题,一看就是给找规律的;不过为什么出题人不给个类似下面这样的样例?

4
-1 -1 1 2

其实答案就是:

$$ans=2^{(n-1)}-1-(sum limits_{i=1}^n2^{(sum[i]-1)}-1)$$

其中$sum[i]$表示$i$的跟班个数。

时间复杂度:$Theta(n+log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int n;
int sum[100001];
long long ans;
long long qpow(long long x,long long y)
{
	long long res=1;
	while(y)
	{
		if(y&1)res=res*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return res;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){int x;scanf("%d",&x);if(x!=-1)sum[x]++;}
	ans=qpow(2,n-1)-1;
	for(int i=1;i<=n;i++)
		ans=(ans-qpow(2,sum[i])+1+mod)%mod;
	printf("%lld",ans);
	return 0;
}

rp++