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\n");
        return 0;
    }
    if(m==0)//特判 
    {
        printf("0\n");
        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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Harry-bh/p/8992508.html