JZOJ6343. 【NOIP2019模拟2019.9.7】Medium Counting

49 篇文章 0 订阅
32 篇文章 1 订阅

Description

在这里插入图片描述
1 ≤ n ≤ 50 , 1 ≤ L ≤ 20 1\leq n \leq 50,1\leq L \leq 20 1n50,1L20

Solution

  • 简单的计数,但是我的考虑方向并不正确,设的状态也不好做,导致正解其实并不难,但是我在考场上没有做出来。
  • 既然已经给定了顺序,那么一段满足条件一定是前几个字符完全一样,后面再区分开来。
  • 如果我们按照从后往前的顺序做,就很好转移,有点类似区间DP。
  • f [ i ] [ l ] [ r ] [ c ] f[i][l][r][c] f[i][l][r][c]表示 l l l r r r的后i位已经确定并且能区分开来,第i位最大的字符为c
  • 枚举一个 r ′ r' r,让r+1~r’的第i位都为字符c’,转移到 f [ i ] [ l ] [ r ′ ] [ c ′ ] f[i][l][r'][c'] f[i][l][r][c]
  • 要满足c<c’,所以用一个前缀和优化一下就好了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 55
#define maxl 22
#define ll long long 
#define mo 990804011
using namespace std;

int n,i,j,k,L,l,r,len[maxn];
char ch;
int s[maxn][maxl];
ll f[maxl][maxn][maxn][27];

int main(){
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		for(ch=getchar();(ch<'a'||ch>'z')&&ch!='?';ch=getchar());
		for(;(ch>='a'&&ch<='z')||ch=='?';ch=getchar()) {
			++len[i];
			if (ch=='?') s[i][len[i]]=-1; else 
				s[i][len[i]]=ch-'a'+1;
		}
		L=max(L,len[i]);
	}
	for(i=1;i<=n;i++) f[L+1][i][i][26]=1;
	for(k=L;k>=1;k--){
		for(l=1;l<=n;l++) if (s[l][k]==0) f[k][l][l][0]=1;
		for(l=1;l<=n;l++) for(r=l;r<=n;r++) {
			for(j=1;j<=26;j++){
				f[k][l][r][j]=f[k][l][r][j-1];
				for(i=r;i>l&&(s[i][k]==-1||s[i][k]==j);i--) 
					f[k][l][r][j]+=f[k][l][i-1][j-1]*f[k+1][i][r][26]%mo;
				if (i==l&&(s[i][k]==-1||s[i][k]==j)) 
					f[k][l][r][j]+=f[k+1][l][r][26];
				f[k][l][r][j]%=mo;
			}
		}
	}
	printf("%lld",f[1][1][n][26]);
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值