Codeforces

Luogu

分析

不难想到 DP。设 $dp_{i,a_1,a_2,\cdots}$ 表示前 $i$ 个字符,字符 $c_j$ 的出现次数模 $m_j$ 等于 $a_j$ 时的方案数。转移枚举在后面填的字符即可。

因为 $\prod m_i\leq 123$,所以后面的状态至多只有 $123$ 种,因此直接矩阵快速幂即可。

实现时需要把后面的状态压成一个数。我的做法是压成 $\Big(\big((a_1m_1)+a_2\big)m_2+a_3\Big)m_3$ 的样子。构造转移矩阵和算答案时可以直接把所有状态搜出来。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef long long ll;

char getc() {
    char c=getchar();
    while (c<'A'||c>'Z') c=getchar();
    return c;
}
ll read() {
    ll X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=123+10,M=1000+10;
const int mod=12345;

ll n; int m,r=1,vis[256];
struct node { char c; int k; } a[M];

struct Matrix {
    int s[N][N];
    Matrix() { memset(s,0,sizeof(s)); }
    int* operator [](int i) { return s[i]; }
} A,Q;
Matrix operator *(Matrix a,Matrix b) {
    Matrix c;
    for (int i=0;i<r;++i)
        for (int j=0;j<r;++j)
            for (int k=0;k<r;++k)
                c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%mod;
    return c;
}
Matrix qpow(Matrix a,ll b) {
    Matrix c=a; --b;
    for (;b;b>>=1,a=a*a) if (b&1) c=c*a;
    return c;
}

void dfs1(int p,char c,int u,int v) {
    if (p>m) { ++Q[u][v]; return; }
    for (int i=0;i<a[p].k;++i)
        dfs1(p+1,c,u*a[p].k+i,v*a[p].k+(i+(a[p].c==c))%a[p].k);
}
int ok[256],ans=0;
void dfs2(int p,int S) {
    if (p>m) {
        int flag=1;
        for (char i='A';i<='Z';++i)
            if (vis[i]&&!ok[i]) { flag=0; break; }
        if (flag) ans=(ans+A[0][S])%mod;
        return;
    }
    int o=ok[a[p].c];
    for (int i=1;i<a[p].k;++i) dfs2(p+1,S*a[p].k+i);
    ok[a[p].c]=1,dfs2(p+1,S*a[p].k);
    ok[a[p].c]=o;
}

int main() {
    n=read(),m=read();
    if (n==0) { puts("1"); return 0; }
    for (int i=1;i<=m;++i) vis[a[i].c=getc()]=1,r*=(a[i].k=read());
    for (char i='A';i<='Z';++i) if (vis[i]) dfs1(1,i,0,0);
    A[0][0]=1; A=A*qpow(Q,n);
    dfs2(1,0); printf("%d\n",ans);
    return 0;
}
最后修改:2020 年 09 月 14 日 08 : 19 PM