题目描述:
题目分析:
记
p
[
c
]
=
∏
c
n
t
[
c
]
p[c]=\prod cnt[c]
p[c]=∏cnt[c]
用
f
[
i
]
[
a
]
[
b
]
[
c
]
[
.
.
.
]
f[i][a][b][c][...]
f[i][a][b][c][...]表示用了i个字母,num[1]%p[1]=a,num[2]%p[2]=b,…
总的状态数是123,枚举下一个字母是哪一个进行转移,用矩阵加速。、
搜索状态进行编号,最后的答案需要枚举每一个限制。
然而我真的非常傻逼地照着这个意思模拟然后代码巨丑无比。。 、
我们需要一点编码(压状态)技巧,保证连续、不重复,就可以用++来遍历每个状态:
记第
i
i
i个限制为
c
[
i
]
,
c
n
t
[
i
]
c[i],cnt[i]
c[i],cnt[i],当前串中i字符出现次数为
n
u
m
[
i
]
num[i]
num[i],基底
b
a
s
e
[
i
]
=
∏
j
=
1
i
c
n
t
[
i
]
base[i]=\prod_{j=1}^icnt[i]
base[i]=∏j=1icnt[i]
那么字符串状态就可以表示为
∑
i
=
1
m
(
n
u
m
[
c
[
i
]
]
%
c
n
t
[
i
]
)
∗
b
a
s
e
[
i
−
1
]
\sum_{i=1}^m(num[c[i]]\%cnt[i])*base[i-1]
∑i=1m(num[c[i]]%cnt[i])∗base[i−1]。
可以看出这样的状态定义是连续、不重复的,且总状态数至多为
∑
i
=
1
m
(
c
n
t
[
i
]
−
1
)
∗
b
a
s
e
[
i
−
1
]
=
∑
i
=
1
m
b
a
s
e
[
i
]
−
b
a
s
e
[
i
−
1
]
=
b
a
s
e
[
m
]
−
b
a
s
e
[
0
]
≤
123
\sum_{i=1}^m(cnt[i]-1)*base[i-1]=\sum_{i=1}^mbase[i]-base[i-1]=base[m]-base[0]\le123
∑i=1m(cnt[i]−1)∗base[i−1]=∑i=1mbase[i]−base[i−1]=base[m]−base[0]≤123
上面这个做法来自这位dalao的博客
Code(这个做法是用的搜索):
#include<bits/stdc++.h>
#define maxn 135
#define LL long long
using namespace std;
const int mod = 12345, Seed = 137;
LL n;
int m,p[maxn],id[28],a[28],cnt,tot,ans;
bool vis[maxn];
char c;
map<LL,int>h;
map<int,bool>ed;
vector<int>t[maxn];
struct Mat{
int s[maxn][maxn];
Mat(){memset(s,0,sizeof s);}
Mat operator * (const Mat &B)const{
Mat ret;
for(int k=1;k<=tot;k++)
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
ret.s[i][j]=(ret.s[i][j]+s[i][k]*B.s[k][j])%mod;
return ret;
}
}f,g;
int H(){
LL ret=0;
for(int i=1;i<=cnt;i++) ret=ret*Seed+(a[i]<p[i]?a[i]:0);
if(h.count(ret)) return h[ret];
else return h[ret]=++tot;
}
void dfs(){
int x=H(),y;vis[x]=1;
for(int i=1;i<=cnt;i++){
a[i]++,g.s[x][y=H()]++;
if(a[i]<p[i]&&!vis[y]) dfs();
a[i]--;
}
}
void solve(int i){
if(i>cnt){
int x=H();
if(!ed.count(x)) ans=(ans+f.s[1][x])%mod,ed[x]=1;
}
else for(auto k: t[i]){
if(k) for(a[i]=k;a[i]<p[i];a[i]+=k) solve(i+1);
else a[i]=0,solve(i+1);
}
}
int main()
{
scanf("%I64d%d",&n,&m);
int x,y;
while(m--){
while(!isalpha(c=getchar()));scanf("%d",&x),y=c-'A';
if(id[y]) p[id[y]]*=x;
else p[id[y]=++cnt]=x;
t[id[y]].push_back(x);
}
dfs();
f.s[1][1]=1;
for(;n;n>>=1,g=g*g) if(n&1) f=f*g;
for(int i=1;i<=cnt;i++)
t[i].push_back(0),sort(t[i].begin(),t[i].end()),unique(t[i].begin(),t[i].end());
solve(1);
printf("%d\n",ans);
}