题解 [CTSC2006]歌唱王国
Desctiption
见题面。
Solution
人类智慧。。。
考虑这样一个赌博游戏,现在有一个猴子,它随机从 \(1\sim n\) 中选一个打出来。现在有若干个赌徒,他们一开始都有 \(\$1\),现在有一个字符串 \(S\),赌徒在第一次押猴子会打 \(S_1\),如果赢了就回收 \(\$ n\) ,如果输了就可以滚他的蛋了。如果赌徒赢了就继续押猴子会打 \(S_2\),如果赢了就回收 \(\$ n^2\) ,否则就可以滚蛋了。以此类推,并且猴子每打一个字都会新加进来一个赌徒。当某一个赌徒不用滚蛋的时候赌场就可以滚蛋了。
我们观察后可以发现这个赌博是一个公平博弈,因为一个赌徒最后的期望财产为 \(1\),所以赌徒和赌场从期望上来讲都是不赚不亏的。接着我们考虑结束前发生了什么。
我们假设 \(S=\{1,4,1,5,1,1,4,1\}\),\(n=5\),那么最后一个赌徒得了 \(\$5\),倒数第三个赌徒得了 \(\$5^3\) ,倒数第八个赌徒得了 \(\$5^8\),其余赌徒都滚蛋了。
又因为这个博弈是公平的,也就是说从期望角度,赌场需要来 \(5^1+5^3+5^8\) 个人才可以。我们另外可以看出,赌徒得的总钱数(即这个题中唱歌期望时间)就是:
\[\sum_{T\in \text{Border S}} n^{|T|}
\]
求 \(\text{Border}\) 可以直接 KMP。
时间复杂度 \(\Theta(n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 100005
#define mod 10000
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,m,t,s[MAXN],f[MAXN],fail[MAXN];
int mul (int a,int b){return a * b % mod;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void Work (int now){
read (m);
for (Int i = 1;i <= m;++ i) read (s[i]);
for (Int i = 2,t = 0;i <= m;++ i){
while (t && s[t + 1] != s[i]) t = fail[t];
if (s[t + 1] == s[i]) ++ t;
fail[i] = t;
}
for (Int i = m;i;i = fail[i]) f[i] = now;
int ans = 0;for (Int i = 1,tmp = n % mod;i <= m;++ i,tmp = mul (tmp,n)) if (f[i] == now) ans = add (ans,tmp);
printf ("%04d\n",ans);
}
signed main(){
read (n,t);
while (t --> 0) Work (t + 1);
return 0;
}