Crime Management Codeforces107D

【原题地址】: Codeforces107D
【题目大意】: 有一种长度为 (n) 的字符串,给定 (m) 种限制,即字符 (c) 出现的次数为 (cnt),若一个字符有多种限制,则满足任意一个即可,求这种字符串有多少个,所有的 $cnt $ 相乘小于等于 (123)
【题解】: 我们可以考虑DP的做法
我们设 maxn[c] 为第 (c) 种字符的所有限制 (cnt) 的乘积
dp[i][a][b][c][d].....[z],表示枚举到字符串的第 (i) 位,每个字符为,出现次数 (\%) maxn[c] 的状态下字符串的总数。
那么最后求答案直接统计合法的方案就行了。

但是这么做空间,时间都是不允许的,所以我们要使用矩阵快速幂来进行优化。

我们可以考虑使用 (map) 来对每种状态重新编号,将状态存入矩阵中进行转移。
矩阵第 (i) 行第 (j) 列如果有值 1,则说明可以转移,最后矩阵的 (n-1) 次幂
就是状态转移了 (n) 次,直接统计第 1 行的合法方案。

我统计答案,预处理矩阵用的DFS

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<vector>
using namespace std;
const int mod=12345;
long long n;
int m,ans=0;
int maxn[30];
vector<int>ok[30];
struct Matrix
{
	int a[125][125];
	Matrix()
	{
		memset(a,0,sizeof(a));
	};
	Matrix operator * (const Matrix &x) const
	{
		Matrix ans=Matrix();
		for(int i=1;i<=123;i++)
		for(int j=1;j<=123;j++)
		{
			for(int k=1;k<=123;k++)ans.a[i][j]+=a[i][k]*x.a[k][j]%mod,ans.a[i][j]%=mod;
			
		}
		return ans;
	}
	Matrix operator ^ (const long long &x) const
	{
		Matrix ans=(*this),temp=(*this);
		long long now=x;
		while(now)
		{
			if(now&1)ans=ans*temp;
			temp=temp*temp;
			now>>=1;
		}
		return ans;
	}
}mat;
struct dat
{
	int val[30];
	bool operator < (const dat& a)const 
	{
		for(int i=1;i<=26;i++)
		{
			if(val[i]==a.val[i])continue;
			return val[i]<a.val[i];
		}
		return false;
	}
}chuzhi;
map<dat,int>mp;
int pcnt=0;
void dfs(int pos,dat now)
{
	if(pos==27)
	{
		mp[now]=++pcnt;
		return ;
	}
	if(maxn[pos]==0)dfs(pos+1,now);
	for(int i=0;i<maxn[pos];i++)
	{
		now.val[pos]=i;
		dfs(pos+1,now);
	}
}
void calc(int pos,dat now)
{
	if(pos==27)
	{
		ans+=mat.a[1][mp[now]];
		ans%=mod;
		return ;
	}
	if(maxn[pos]==0)calc(pos+1,now);
	for(int i=0;i<maxn[pos];i++)
	{
		bool flag=false;
		for(int j=0;j<ok[pos].size();j++)
		if(i%ok[pos][j]==0){
			flag=true;
			break;
		}
		if(flag)
		{
			now.val[pos]=i;
			calc(pos+1,now);
		}
	}
}
char A;
int x,c;
int main()
{
	scanf("%lld%d",&n,&m);
	if(n==0)//特判 
	{
		printf("1
");
		return 0;
	}
	if(m==0)//特判 
	{
		printf("0
");
		return 0;
	}
	for(int i=1;i<=m;i++)
	{
		scanf(" %c %d",&A,&x);
		c=A-'A'+1;
		if(maxn[c]==0)maxn[c]=x;
		else maxn[c]*=x;
		ok[c].push_back(x);
		
		
	}
	dfs(1,chuzhi);
	for(map<dat,int>::iterator i=mp.begin();i!=mp.end();i++)
    {
        int s=i->second;
        dat now=i->first;
        for(int j=1;j<=26;j++)
        {
            if(maxn[j]==0)continue;
            dat temp=now;
            temp.val[j]=(temp.val[j]+1)%maxn[j];
            mat.a[s][mp[temp]]++;
        }
    }
    mat=mat^((long long)n-1);
    calc(1,chuzhi);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Harry-bh/p/8992508.html