• 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;
    }
    
  • 相关阅读:
    codeforces 707D-(DFS+bitset)
    codeforces Educational Codeforces Round 16-E(DP)
    codeforces 597C (树状数组+DP)
    codeforces #round363 div2.C-Vacations (DP)
    Codeforces Round #365 (Div. 2)-D Mishka and Interesting sum(树状数组)
    codeforces round367 div2.C (DP)
    June Challenge 2018 Division 2
    Codeforces Round #487 (Div. 2)
    Educational Codeforces Round 45 (Rated for Div. 2)
    [Offer收割]编程练习赛63
  • 原文地址:https://www.cnblogs.com/Harry-bh/p/8992508.html
Copyright © 2020-2023  润新知