传送门

又是神仙DP

发现如果只有两个串就很好做了

于是这个神仙DP定义就从这里下手:令 $dp[p][c][l][r] 表示在 \([s_l, s_r]\) 这段字符串中,考虑从第 \(p\) 个位置开始的后缀,并要求这个字符至少为 \(c\)

考虑转移,因为这里有个「至少」,第一个转移是直接从 \(dp[p][c+1][l][r]\) 继承过来

考虑第二个转移

发现在 \([l, r]\) 中一定存在一个 \(c\) 到 \(c+1\) 的分界点,我们枚举这个分界点

同时如果我们强令为 \(c\) 的那些数与输入冲突了就break掉

于是这部分的转移方程为

\[dp[p][c][l][r] += \sum\limits_{i=l}^{i\leqslant r} dp[p+1][0][l][i]*dp[p][c+1][i+1][r]
\]

这样就(在一定程度上)转化成了对两个字符串的处理

记得要把长度不够的串用‘a'-1补成一样长

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ull unsigned long long
#define reg register int
//#define int long long int n;
char s[55][25];
int len[55], maxl;
const ll mod=990804011ll, base=131;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;} namespace force{
ull p[25];
inline ull hashing(ull* h, int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
ll dfs(int u, char* t, ull ht, ull hs, bool lim) {
//cout<<"dfs "<<u<<' '<<ht<<' '<<hs<<' '<<lim<<endl;
if (u>n) return 1;
ull h[25]; h[0]=0; bool full=1;
//cout<<"len: "<<len[u]<<endl;
for (reg i=1; i<=len[u]; ++i) {
//cout<<"i: "<<i<<endl;
if (s[u][i]=='?') {
full=0; ll ans=0;
//cout<<"pos1"<<endl;
for (reg j=(lim?t[i]-'a'+1:0); j<26; ++j) {
s[u][i]='a'+j; h[i]=h[i-1]*base+s[u][i];
ans+=dfs(u, t, ht, h[i], lim&&(s[u][i]==t[i]));
}
s[u][i]='?';
return ans;
}
else {
h[i]=h[i-1]*base+s[u][i];
if (lim && s[u][i]<t[i]) return 0;
if (lim && s[u][i]!=t[i]) lim=0;
}
}
if (full && !lim) return dfs(u+1, s[u], h[len[u]], 0, 1);
return 0;
}
void solve() {
printf("%lld\n", dfs(1, s[0], 0, 0, 0));
exit(0);
}
} namespace task1{
ull p[25];
struct st{int u; ull ht, hs; bool lim; st(int a, ull b, ull c, bool d):u(a),ht(b),hs(c),lim(d){}};
struct st_hash{inline size_t operator () (st a) const {return hash<ull>()(a.ht*a.hs);}};
inline bool operator == (st a, st b) {return a.u==b.u&&a.ht==b.ht&&a.hs==b.hs&&a.lim==b.lim;}
unordered_map<st, ll, st_hash> mp{5000, st_hash()};
inline ull hashing(ull* h, int l, int r) {return h[r]-h[l-1]*p[r-l+1];}
ll dfs(int u, char* t, ull ht, ull hs, bool lim) {
//cout<<"dfs "<<u<<' '<<ht<<' '<<hs<<' '<<lim<<endl;
if (u>n) return 1;
st sit(u, ht, hs, lim);
if (mp.find(sit)!=mp.end()) return mp[sit];
ull h[25]; h[0]=0; bool full=1;
//cout<<"len: "<<len[u]<<endl;
for (reg i=1; i<=len[u]; ++i) {
//cout<<"i: "<<i<<endl;
if (s[u][i]=='?') {
full=0; ll ans=0;
//cout<<"pos1"<<endl;
for (reg j=(lim?t[i]-'a'+1:0); j<26; ++j) {
s[u][i]='a'+j; h[i]=h[i-1]*base+s[u][i];
ans+=dfs(u, t, ht, h[i], lim&&(s[u][i]==t[i])), ans%=mod;
}
s[u][i]='?';
mp[sit]=ans;
return ans;
}
else {
h[i]=h[i-1]*base+s[u][i];
if (lim && s[u][i]<t[i]) {mp[sit]=0; return 0;}
if (lim && s[u][i]!=t[i]) lim=0;
}
}
if (full && !lim) {
mp[sit]=dfs(u+1, s[u], h[len[u]], 0, 1);
return mp[sit];
}
return 0;
}
void solve() {
printf("%lld\n", dfs(1, s[0], 0, 0, 0)%mod);
exit(0);
}
} namespace task{
ll dp[25][30][52][52];
ll dfs(int p, int c, int l, int r) {
//cout<<"dfs "<<p<<' '<<c<<' '<<l<<' '<<r<<endl;
if (~dp[p][c][l][r]) return dp[p][c][l][r];
if (l>r) return dp[p][c][l][r]=1;
if (p>maxl) return dp[p][c][l][r]=(l==r);
if (c>26) return dp[p][c][l][r]=0;
dp[p][c][l][r]=dfs(p, c+1, l, r);
for (int i=l; i<=r; ++i) {
//if (s[i][p]!=27&&s[i][p]!=c) break;
if (!(s[i][p]==c || (s[i][p]==27&&c))) break;
md(dp[p][c][l][r], dfs(p+1, 0, l, i)*dfs(p, c+1, i+1, r)%mod);
}
return dp[p][c][l][r];
}
void solve() {
memset(dp, -1, sizeof(dp));
printf("%lld\n", dfs(1, 0, 1, n));
exit(0);
}
} signed main()
{
scanf("%d", &n);
for (reg i=1; i<=n; ++i) {
scanf("%s", s[i]+1);
len[i]=strlen(s[i]+1);
maxl=max(maxl, len[i]);
for (int j=1; j<=len[i]; ++j)
if (s[i][j]=='?') s[i][j]=27;
else s[i][j]-='`';
}
//if (n*maxl<=10) force::solve();
//else task1::solve();
task::solve(); return 0;
}

题解 Medium Counting的更多相关文章

  1. 【题解】Counting D-sets(容斥+欧拉定理)

    [题解]Counting D-sets(容斥+欧拉定理) 没时间写先咕咕咕. vjCodeChef - CNTDSETS 就是容斥,只是难了一二三四五\(\dots \inf\)点 题目大意: 给定你 ...

  2. 20210819 Emotional Flutter,Medium Counting,Huge Counting,字符消除2

    考场 T1 一下想到了这题,将白块缩短 \(s\) 后维护类似的区间即可. T2 T3 俩计数,直接跳了. T4 的可行 \(t\) 集合相同相当与从 \(n\) 往前跳 kmp 数组,途径点相同,从 ...

  3. LeetCode题解之Counting Bits

    1.题目描述 2.问题分析 利用bitset. 3 代码 vector<int> countBits(int num) { vector<int> v; ; i <= n ...

  4. PAT甲题题解-1004. Counting Leaves (30)-统计每层叶子节点个数+dfs

    统计每层的叶子节点个数建树,然后dfs即可 #include <iostream> #include <cstdio> #include <algorithm> # ...

  5. PAT甲题题解-1049. Counting Ones-数学问题

    n位数,总共有0~10^n-1共计10^n个数那么所有数出现的总次数变为n*(10^n)个数1出现的次数便是十分之一,所以n位数中,1出现的次数为n*10^(n-1)知道这一个后,接下来就方便求了. ...

  6. PAT甲题题解-1115. Counting Nodes in a BST (30)-(构建二分搜索树+dfs)

    题意:给出一个序列,构建二叉搜索树(BST),输出二叉搜索树最后两层的节点个数n1和n2,以及他们的和sum: n1 + n2 = sum 递归建树,然后再dfs求出最大层数,接着再dfs计算出最后两 ...

  7. [考试反思]1114csp-s模拟测试115:零迟

    最后一次了,允许自己混进榜里吧. 没有心态,原题不会做(真的忘了) T2的搜索没有分. 「 零 · 迟 」:酷刑 只有在最后的时刻才开始意识到,一切的一切都已经晚了. 就在眼前了.没有机会了. 退役, ...

  8. noip模拟44[我想我以后会碰见计数题就溜走的]

    noip模拟44 solutions 这一场抱零的也忒多了,我也只有45pts 据说好像是把几套题里面最难的收拾出来让我们考得 好惨烈啊,这次的考试我只有第一题骗了40pts,其他都抱零了 T1 Em ...

  9. 2021.8.19考试总结[NOIP模拟44]

    T1 emotional flutter 把脚长合到黑条中. 每个黑条可以映射到统一区间,实际操作就是左右端点取模.长度大于$k$时显然不合法. 然后检查一遍区间内有没有不被黑条覆盖的点即可. 区间端 ...

随机推荐

  1. B 站崩了,总结下「高可用」和「异地多活」

    你好,我是悟空. 一.背景 不用想象一种异常场景了,这就真实发生了:B 站晚上 11 点突然挂了,网站主页直接报 404. 手机 APP 端数据加载不出来. 23:30 分,B 站做了降级页面,将 4 ...

  2. Luogu P4553 80人环游世界

    link 题目大意 自东向西有 \(n\) 个国家.有 \(m\) 个人,他们可以选择 \(n\) 个国家中任意一个开始,任意一个结束,但路线必须自东向西,且第 \(i\) 个国家必须恰好经过 \(v ...

  3. webpack 快速入门 系列 —— 性能

    其他章节请看: webpack 快速入门 系列 性能 本篇主要介绍 webpack 中的一些常用性能,包括热模块替换.source map.oneOf.缓存.tree shaking.代码分割.懒加载 ...

  4. shell脚本编写规范和相关变量类型

    shell编程规范与变量    一.shell脚本概述    ① 什么是shell? Linux中有哪些shell?    ② shell的作用   ③ 用户的登录shell    ④ shell脚本 ...

  5. 深度解析CSS中的单位以及区别

    css中有几个不同的单位表示长度,使用时数字加单位.如果长度为0,则可以省略单位. 长度单位可分为两种类型:相对和绝对. 绝对长度 绝对长度单位是一个固定的值,反应真实的物理尺寸,不依赖于显示器.分辨 ...

  6. [刘阳Java]_CSS菜单侧边栏制作

    再来写一个菜单侧边栏的制作,先看截图 源代码如下 <!DOCTYPE html> <html> <head> <meta charset="UTF- ...

  7. Spring RestTemplate 之post请求

    ●post请求:在RestTemplate中,POST请求可以通过如下三个方法来发起,但post提交方式又有两种 formData 和 payLoad,而且接口设计与传统的浏览器使用的提交方式又有差异 ...

  8. 【Mysql】InnoDB 引擎中的页目录

    一.页目录和槽 接上一篇,现在知道记录在页中按照主键大小顺序串成了单链表. 那么我使用主键查询的时候,最顺其自然的办法肯定是从第一条记录,也就是 Infrimum 记录开始,一直向后找,只要存在总会找 ...

  9. Java 并发之 Fork/Join 框架

    什么是 Fork/Join 框架 Fork/Join 框架是一种在 JDk 7 引入的线程池,用于并行执行把一个大任务拆成多个小任务并行执行,最终汇总每个小任务结果得到大任务结果的特殊任务.通过其命名 ...

  10. Leetcode:面试题 04.04. 检查平衡性

    Leetcode:面试题 04.04. 检查平衡性 Leetcode:面试题 04.04. 检查平衡性 Talk is cheap . Show me the code . /** * Definit ...