传送门
orz ymd
考虑构造生成函数:设\(F(x) = \sum\limits_{i=0}^\infty f_ix^i\),其中\(f_i\)表示答案为\(i\)的概率;又设\(G(x) = \sum\limits_{i=0}^\infty g_ix^i\),其中\(g_i\)表示经过了\(i\)步之后还没有结束的概率。那么答案显然是\(F'(1)\)。
考虑在还没有结束的序列之后加入一个字符,那么有可能结束也有可能没有结束,即\(F(x) + G(x) = xG(x) + 1\)。
两边求导并将\(x=1\)代入可以得到\(F'(1) = G(1)\)。
接下来考虑在还没有结束的序列之后加入当前需要匹配的字符串,那么一定会结束,但有可能已经存在一个前缀满足条件。设\(a_i\)表示原字符串是否有长度为\(i\)的border,那么不难得到\(G(x)(\frac{x}{n})^m = \sum\limits_{i=1}^m a_iF(i)(\frac{x}{n})^{m-i}\)。
将\(x=1\)代入可以得到\(G(1) = \sum\limits_{i=1}^m a_in^i\)
那么使用哈希或者KMP求出所有的\(a_i\)即可求出答案。
#include
//this code is written by Itst
using namespace std;
int read(){
int a = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48; c = getchar();
}
return a;
}
#define int long long
const int _ = 1e5 + 7;
const int seed = 2344259 , MOD = 134093753;
int powsd[_] , N , T , M;
namespace Hashing{
int val[_];
void init(int len){
for(int i = 1 ; i <= len ; ++i)
val[i] = (1ll * val[i - 1] * seed + read()) % MOD;
}
int qry(int l , int r){return (val[r] - val[l - 1] * powsd[r - l + 1] % MOD + MOD) % MOD;}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
powsd[0] = 1; powsd[1] = seed;
for(int i = 2 ; i <= 1e5 ; ++i)
powsd[i] = 1ll * powsd[i - 1] * seed % MOD;
N = read() % 10000; T = read();
for(int i = 1 ; i <= T ; ++i){
int L = read() , sum = 0 , tms = N; Hashing::init(L);
for(int j = 1 ; j <= L ; ++j , tms = tms * N % 10000)
if(Hashing::qry(1 , j) == Hashing::qry(L - j + 1 , L))
sum = (sum + tms) % 10000;
printf("%04lld\n" , sum);
}
return 0;
}