传送门

又是神仙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. 从源码角度谈谈MySQL "Too many open files"错误的根本原因

    "Too many open files"是一个比较常见的错误,不仅仅是在 MySQL 中.只要是在 Linux 中启动的进程,都有可能遇到这个错误. 究其原因,是进程打开的文件描 ...

  2. C语言:基本数据类型及表示范围

    类型名称 标识符 printf()标志 占据 范围 无符号 unsigned 范围 类型名称 类型标识符    printf标志   占字节数           表示范围              ...

  3. kali之Metasploit入门

    前言 不得不说Metasploit 目前是世界领先的黑客框架.它在某种程度上被几乎每个黑客/渗透者使用.因此,如果您想进入网络安全/渗透测试行业并有所成就,您就必须要需要熟悉它. Metasploit ...

  4. nacos配置本地多个实例(伪集群)

    在本地配置多个nacos实例(伪集群),一般就是配置多个nacos端口,并启动多个startup.sh脚本.网上一些博客通过修改startup.sh脚本来指定不同nacos端口,比如:./startu ...

  5. IO编程之File类

    File类是java.io包下代表与平台无关的文件及目录,程序操作文件和目录都可以通过File类来完成.值得指出的是,不管是文件还是目录都可以通过File类来操作.File能新建.删除.重命名文件和目 ...

  6. 第九篇 -- 可以上网,连WIFI弹出网页

    最近在调试WIFI模块时,程序路径没走对,导致运行了其他的函数,修改了配置文件,之后每次连接WIFI时都会弹出网页,并且明明可以上网,下面电脑符号那儿还会出现黄标,甚是心烦.上网搜索一番,终是解决了. ...

  7. 远程访问Jupyter Notebook的两种方式:命令行和配置文件

    远程访问Jupyter Notebook的两种方式:命令行和配置文件 相关配置:Ubuntu 16.04服务器,本地Win10,使用了Xshell,Xftp工具. 相关配置主要分为三步: 服务器上的J ...

  8. HCNA Routing&Switching之GVRP

    前文我们了解了不同vlan间路由相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15110336.html,今天我们来聊一聊vlan动态注册相关话题: ...

  9. 造轮子系列之RPC 1:如何从零开始开发RPC框架

    前言 RPC 框架是后端攻城狮永远都绕不开的知识点,目前业界比较知名有 Dubbo.Spring Cloud 等.很多人都停留在了只会用的阶段,作为程序猿,拥有好奇心深入学习,才能有效提高自己的竞争力 ...

  10. DVWA靶场练习-Command Injection命令注入

    Command Injection 原理 攻击者通过构造恶意参数,破坏命令的语句结构,从而达到执行恶意命令的目的.