题解/算法 {E - Alphabet Tiles}

题解/算法 {E - Alphabet Tiles}

@LINK: https://atcoder.jp/contests/abc358/tasks/abc358_e;

定义: 我们称一个字符串S是合法的, 当其中每个字符出现的次数 是[0, Ci]范围的(Ci是题目给定的);

这个题 没找到正确思路的 错误做法还是很多的… 比如你可能想到不同颜色小球的排列数 即比如C1,C2,C3表示不同颜色小球的个数 那么其排列数是(C1+C2+C3)! / C1! / C2! / C3!, 但是 他的前提是 你每种颜色的个数C1,C2是固定的确定的, 可是 这个题里 他的个数是[0, Ci]范围 是个变数;
我们直接讲正确做法;

DP(i,j): i[0,25], j[0,K]'A' + 0,1,...,i这些字符构成长度为j的合法字符串的个数;
然后对于(i,j) 我们枚举再往里面 加入x个(i+1)元素 (0<= x <= C[i+1]), 比如A1, A2, ..., Aj 我们要往里面 再加入xB (B != Ai); 比如j=2, x=2 那么会有[B,B,A1,Aj], [B,A1,B,Aj], [B,A1,Aj,B], [A1,B,B,Aj], [A1,B,Aj,B], [A1,Aj,B,B]);
这个问题 等价于是: 将这个x这个元素 放到原序列A1...Aj缝隙里面 他有j+1个缝隙, 也就是隔板法Split0;
时间是26 * 1e3 * 1e3, 因此隔板法要做到O(1) 你要预处理二维数组;

最终答案是DP[25][ 1|2|...|K]之和;

int K; cin>> K;
vector<int> Cont( 26); for( auto & i : Cont){ cin>> i;}
Mod_ DP[ 26][ 1003];
std::memset( DP, 0, sizeof( DP));
FOR_( I, 0, 25){
    if( I == 0){
        FOR_( J, 0, Cont[I]){
            DP[ I][J] = 1;
        }
        continue;
    }
    FOR_( Jpre, 0, K){
        FOR_( cont, 0, std::min( Cont[I], K-Jpre)){
            DP[ I][ Jpre + cont] += (DP[I-1][Jpre] * ___Combinatorics_Split0<Mod_, int>( cont, Jpre+1));
        }
    }
}
Mod_ ANS = 0;
FOR_( i, 1, K){ ANS += DP[25][i];}
cout<< ANS.Value<< "\n";
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值