题意
做法
令(f_{i,j})为第i轮得到的序列,假设j后的状态,状态维护序列中的答案,(pre_i,suf_i)
(suf_i):其长度为(i)的后缀是否能成为可行串长度为(i)的前缀
(pre_i):其长度为(n-i)的前缀是否能成为可行串长度为(n-i)的后缀
合并类似于线段树,然后(pre,suf)用bitset优化
code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const ll inf = 2e18;
const int N = 3e4 + 10;
const int maxn = 2000020;
const ll mod = 1e9 + 7;
struct node{
ll num,len;
bitset <N> pre,suf;
node() { num = len = 0; pre.reset(),suf.reset(); }
}f[70][62];
int gen[120],n,m,d,B[N];
ll l,r,pow_[70];
int a[maxn];
bitset <N> all;
node merge(const node &a,const node &b){
if ( !a.len ) return b;
node res;
res.len = a.len + b.len;
res.pre = a.pre , res.suf = b.suf; //pre和suf中包含了长度1..n-1的所有信息,所以合并的时候直接&就好
res.num = a.num + b.num;
if ( a.len <= n - 2 ) res.pre &= (b.pre >> a.len) | (all << (n - 1 - a.len));
if ( b.len <= n - 2 ) res.suf &= (a.suf << b.len) | (all >> (n - 1 - b.len));
if ( res.len >= n ){
bitset<N> tmp = a.suf & b.pre;
if ( a.len <= n - 2 ) tmp &= all >> (n - 1 - a.len); //如果a的长度不足,则删除高位
if ( b.len <= n - 2 ) tmp &= all << (n - 1 - b.len); //删除低位
res.num += tmp.count();
}
return res;
}
void init(){
pow_[0] = 1;
rep(i,1,64) pow_[i] = pow_[i - 1] * d;
int c = 0;
while ( pow_[c + 1] < r ) c++;
rep(i,1,n - 1) all[i] = 1;
rep(j,0,m){
f[0][j].len = 1;
if ( n == 1 ) f[0][j].num = j <= B[1];
else{
//把没有出现的位置看成0
//这样便于合并、否则每次合并还需要check整段是否合法
rep(k,1,n){
f[0][j].pre[k - 1] = j <= B[k];
f[0][j].suf[k] = j <= B[k];
}
}
}
rep(i,1,c){
rep(j,0,m){
rep(k,0,d - 1){
f[i][j] = merge(f[i][j],f[i - 1][(j + gen[k]) % m]);
}
}
}
}
ll solve(ll n){
int c = 0;
while ( pow_[c + 1] < n ) c++;
int add = 0; node res;
repd(i,c,0){
rep(j,0,d - 1){
if ( n >= pow_[i] ){
n -= pow_[i];
res = merge(res,f[i][(gen[j] + add) % m]);
}
else{
add += gen[j];
break;
}
}
}
cout<<res.num<<endl;
return res.num;
}
int main(){
scanf("%d %d",&d,&m);
rep(i,0,d - 1) scanf("%d",&gen[i]);
scanf("%d",&n);
rep(i,1,n) scanf("%d",&B[i]);
cin>>l>>r;
init();
cout<<solve(r) - solve(l + n - 2)<<endl;
}
题外话
降智...