传送门

又是神仙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. webpack(10)webpack-dev-server搭建本地服务器

    前言 当我们使用webpack打包时,发现每次更新了一点代码,都需要重新打包,这样很麻烦,我们希望本地能搭建一个服务器,然后写入新的代码能够自动检测出来,这时候就需要用到webpack-dev-ser ...

  2. U149791 正多边形变换

    原博客网页--洛谷博客 题目地址 如果您对群论有所了解,那么本题就是对二面体群 \(D_{2n}\) 的简单实现,您可以直接跳到代码部分.下面的解题思路只是对二面体群 \(D_{2n}\) 的构造思路 ...

  3. 20道Java实习生笔试面试选择题(内附答案解析)

    ​1.以下对继承的描述错误的是(A) A.Java中的继承允许一个子类继承多个父类 B.父类更具有通用性,子类更具体 C.Java中的继承存在的传递性 D.当实例化子类时会递归调用父类中的构造方法 解 ...

  4. VisibleDeprecationWarning , Creating an ndarray from ragged nested sequences... 警告怎么办

    我不是完美主义,但是至少,我在做实验的时候不能容忍有 warning 的出现. 今天使用 tensorflow.keras.datasets中的 imdb 数据集,使用 imdb.load_data( ...

  5. C语言代码段

    /* 功 能:将str字符串中的oldstr字符串替换为newstr字符串 * 参 数:str:操作目标 oldstr:被替换者 newstr:替换者 * 返回值:返回替换之后的字符串 */ char ...

  6. C语言字符串处理库函数大全(转)

    一.string.h中字符串处理函数 在头文件<string.h>中定义了两组字符串函数.第一组函数的名字以str开头:第二组函数的名字以mem开头. 只有函数memmove对重叠对象间的 ...

  7. gitlab部署及汉化

    目录 Git 简介 部署 1. 配置yum源(推荐) 2. 安装 配置GitLab 1.加载配置 2.修改git默认访问端口 gitlab.rb unicorn.rb gitlab-http.conf ...

  8. C语言:字符型数据(常量)

    字符型数据就是字符. 字符型数据的表示 字符型数据是用单引号括起来的一个字符.例如:'a'.'b'.'='.'+'.'?'都是合法字符型数据.在C语言中,字符型数据有以下特点: 字符型数据只能用单引号 ...

  9. uni-app中当uni.navigateTo传的参数为object时,通过传递的不同参数,在显示单页面内通过v-if判断显示出对应的内容(可实现多页面效果)

    通过uni-app中当uni.navigateTo传的参数为object时,通过传递的不同参数,在显示单页面内通过v-if判断显示出对应的内容(可实现多页面效果) 起始页跳转到对应页面,并传递参数(o ...

  10. 手写一个超简单的Vue

    基本结构 这里我根据自己的理解模仿了Vue的单文件写法,通过给Vue.createApp传入参数再挂载元素来实现页面与数据的互动. 其中理解不免有错,希望大佬轻喷. 收集数据 这里将Vue.creat ...