[CF107D] Crime Management

\(\text{Problem}:\)Crime Management

\(\text{Solution}:\)

\(m_{i}\) 表示第 \(i\) 个字符限制的乘积。设 \(f_{i,a,b,...,z}\) 表示枚举到字符串第 \(i\) 位,每个字符 \(i\) 出现次数模 \(m_{i}\) 状态下字符串总数。考虑多维坐标重标号,有 \((a\times m_{2}+b)\times m_{3}+\cdot\cdot\cdot\)

不难发现,状态总数最多只有 \(123\) 种。这提示我们用矩阵表示出状态 \(s\rightarrow t\) 的转移,利用矩阵快速幂即可求得 \(f_{n}\)。注意上面的 \(dp\) 是不考虑合法性的,故最后枚举所有状态,将合法状态计入答案即可。时间复杂度 \(O((\prod\limits m_{i})^{2}\log n)\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=125, Mod=12345;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
} char inp[2];
int n,Q,m[N],up=1;
vector<int> lim[N];
struct Matrix
{
	int a[N][N];
	inline Matrix() { memset(a,0,sizeof(a)); }
}bs,ans;
inline Matrix operator * (Matrix x,Matrix y)
{
	Matrix res;
	for(ri int i=0;i<up;i++)
	for(ri int k=0;k<up;k++)
	for(ri int j=0;j<up;j++)
	res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j])%Mod;
	return res;
}
inline Matrix ksc(Matrix x,int p)
{
	Matrix res;
	for(ri int i=0;i<=up;i++) res.a[i][i]=1;
	for(;p;p>>=1, x=x*x) if(p&1) res=res*x;
	return res;
}
signed main()
{
	n=read(), Q=read();
	for(ri int i=1;i<=Q;i++)
	{
		scanf("%s",inp);
		int w=read();
		int id=inp[0]-'A';
		if(!m[id]) m[id]=w;
		else m[id]*=w;
		lim[id].eb(w);
	}
	for(ri int i=0;i<26;i++) if(m[i]) up*=m[i];
	for(ri int i=0;i<up;i++)
	{
		int S=i;
		int tm=1;
		for(ri int j=25;~j;j--)if(m[j])
		{
			int now=S%m[j];
			S/=m[j];
			int id=i-now*tm;
			now++, now%=m[j];
			id+=now*tm;
			tm*=m[j];
			bs.a[id][i]++;
		}
	}
	ans=ksc(bs,n);
	int ot=0;
	for(ri int i=0;i<up;i++)
	{
		int S=i;
		int cal=1;
		for(ri int j=25;~j;j--)if(m[j])
		{
			int now=S%m[j];
			S/=m[j];
			int flg=0;
			for(auto k:lim[j]) flg|=(now%k==0);
			if(!flg) { cal=0; break; }
		}
		ot=(ot+cal*ans.a[0][i]%Mod)%Mod;
	}
	printf("%lld\n",ot);
	return 0;
}
posted @ 2021-04-28 09:10  zkdxl  阅读(52)  评论(1编辑  收藏  举报