题面

有一个字符串

s

\tt s

s 和一个有理数

k

\tt k

k,可以进行如下操作任意次:

  • 选一个当前串中存在的字符

    x

    \tt x

    x ,令

    i

    1

    ,

    i

    2

    ,

    .

    .

    .

    ,

    i

    m

    \tt i_1,i_2,...,i_m

    i1​,i2​,...,im​ 为字符

    x

    \tt x

    x 存在的

    m

    \tt m

    m 个位置。如果满足

    k

    (

    i

    m

    i

    1

    +

    1

    )

    m

    \tt k\cdot(i_m-i_1+1)\leq m

    k⋅(im​−i1​+1)≤m ,那么可以再选一种不同的当前串中存在的字符

    y

    \tt y

    y ,把所有字符

    x

    \tt x

    x 变成字符

    y

    \tt y

    y 。

不论进行多少次操作,最终要求整个字符串只存在一种字符

z

\tt z

z 。求所有可能的

z

\tt z

z 。

Input

第一行三个整数

n

,

a

,

b

\tt n,a,b

n,a,b ,其中

a

b

=

k

\tt \frac{a}{b}=k

ba​=k 。

第二行一个长为

n

\tt n

n 的由小写字母组成的字符串

s

\tt s

s ,串中不包含 ‘t’,‘r’,‘y’,‘g’,‘u’,‘b’ 六种字符

范围

1

n

5

000

,

1

a

b

100

000

\tt 1\leq n\leq 5\,000,1\leq a\leq b\leq100\,000

1≤n≤5000,1≤a≤b≤100000

1500

m

s

,

32

m

b

\tt 1500\,ms,32\,mb

1500ms,32mb .

题解

经历了前面几道黑题的洗礼,一看到这题的样例及解释,就有种不会做的感觉。

我们细读一遍题,慢慢理一下思路。

首先,在

26

\tt26

26 种字母之中,排除了

6

\tt6

6 种,剩下了

20

\tt20

20 种,刚好是可以做状压的数据范围。

会不会这么巧呢?我们不妨试试。

不难发现,一种字符只能操作一次。

既然最终只有一种字符

z

\tt z

z,那么上一步,就是把另一种字符的所有位置进行操作,而这些位置原本是除了

z

\tt z

z 以外的其它字符位置的并集。倒推回去,中间状态就是把一个字符集

S

\tt S

S 进行操作,此时字符集

S

\tt S

S 中所有字符的所有原先位置上,都有着相同的字符(该字符是什么不重要)。

不妨设

l

e

n

g

t

h

S

\tt length_S

lengthS​ 为字符集

S

\tt S

S 最右边的位置 - 最左边的位置 + 1,

c

n

t

S

\tt cnt_S

cntS​ 为

S

\tt S

S 占据的位置数量。

那么我们定义一个

D

P

\tt DP

DP ,

d

p

[

i

]

\tt dp[i]

dp[i](bool) 表示字符集

i

\tt i

i 是/否能被操作,那么有如下性质:

  1. d

    p

    [

    0

    ]

    =

    1

    \tt dp[0]=1

    dp[0]=1 。

  2. i

    =

    {

    x

    }

    \tt i=\{x\}

    i={x} 时,如果字符

    x

    \tt x

    x 一开始就能被操作,也就是说

    k

    l

    e

    n

    g

    t

    h

    x

    c

    n

    t

    x

    \tt k\cdot length_x\leq cnt_x

    k⋅lengthx​≤cntx​ ,那么

    d

    p

    [

    i

    ]

    =

    1

    \tt dp[i]=1

    dp[i]=1,这可以当作一种边界情况处理。

  3. 对于一种字符

    x

    \tt x

    x ,一开始的

    x

    \tt x

    x 是不能被操作的,但是能够让集合

    i

    x

    \tt i-x

    i−x 的字符被操作、变成字符

    x

    \tt x

    x,然后整体又能被操作了,那么

    d

    p

    [

    i

    ]

    =

    1

    \tt dp[i]=1

    dp[i]=1。也就是说,如果存在

    x

    i

    \tt x\in i

    x∈i ,满足

    d

    p

    [

    i

    x

    ]

    =

    1

    ,

    k

    l

    e

    n

    g

    t

    h

    i

    x

    c

    n

    t

    i

    x

    \tt dp[i-x]=1,k\cdot length_{i-x}\leq cnt_{i-x}

    dp[i−x]=1,k⋅lengthi−x​≤cnti−x​ 且

    k

    l

    e

    n

    g

    t

    h

    i

    c

    n

    t

    i

    \tt k\cdot length_{i}\leq cnt_{i}

    k⋅lengthi​≤cnti​ ,那么

    d

    p

    [

    i

    ]

    =

    1

    \tt dp[i]=1

    dp[i]=1 。

  4. i

    =

    S

    1

    S

    2

    \tt i=S_1\cup S_2

    i=S1​∪S2​,且

    S

    1

    S

    2

    =

    ,

    d

    p

    [

    S

    1

    ]

    =

    1

    ,

    d

    p

    [

    S

    2

    ]

    =

    1

    \tt S_1\cap S_2=\empty,dp[S_1]=1,dp[S_2]=1

    S1​∩S2​=∅,dp[S1​]=1,dp[S2​]=1 时,即两个不相交的字符集分别能被操作。相当于它们的并集也能被操作了,于是

    d

    p

    [

    i

    ]

    =

    1

    \tt dp[i]=1

    dp[i]=1 。

某个字符

z

\tt z

z 能成为最终字符,就意味着

d

p

[

U

z

]

=

1

\tt dp[U-z]=1

dp[U−z]=1 ,在最后一步,除了

z

\tt z

z 以外的字符能全部变成

z

\tt z

z。

此时的复杂度是

Θ

(

3

C

)

\tt \Theta(3^{|C|})

Θ(3∣C∣) 级别的,达不到需求。瓶颈就在第四条性质,也就是第二条转移上。

我们可以找个性质优化一下。我们发现对于第二种转移,找

i

\tt i

i 的子集

S

1

\tt S_1

S1​,

S

2

\tt S_2

S2​ ,如果字符集

S

1

\tt S_1

S1​ 的右端点小于

S

2

\tt S_2

S2​ 的左端点,或

S

1

\tt S_1

S1​ 的左端点大于

S

2

\tt S_2

S2​ 的右端点,这样的转移才需要考虑。否则的话,可以把

S

1

\tt S_1

S1​ 进行操作,变成

S

2

\tt S_2

S2​ 的一些字符,最终把

S

2

\tt S_2

S2​ “吞”掉,表现为第一种转移。

原因在于,一个字符集能被操作的本质是,在它的最小被覆盖区间内,它自己的浓度大于等于

k

\tt k

k 。如果两种字符集分别能被操作,且彼此有交的话,一个吞掉另一个后,浓度只会增大。浓度增大后,就更能被操作了,这个不难理解。

因此,我们把每种字符按照最左位置排序,选

i

\tt i

i 的子集时,就只选前缀,这样就把复杂度降成了

Θ

(

C

2

C

)

\tt \Theta(|C|2^{|C|})

Θ(∣C∣2∣C∣) 。

CODE

#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 5005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
char ss[MAXN];
int a[MAXN];
char denote[30];
int pos[257];
short ll[1<<20|5],rr[1<<20|5],cnt[1<<20|5];
bool dp[1<<20|5];
int b[30];
bool cmp(int a,int b) {
return ll[1<<a] < ll[1<<b];
}
int main() {
n = read();
LL ka = read(),kb = read();
int tool_0_cnt = -1;
for(char i = 'a';i <= 'z';i ++) {
if(i != 't' && i != 'r' && i != 'y' && i != 'g' && i != 'u' && i != 'b') {
pos[i] = ++ tool_0_cnt;
denote[tool_0_cnt] = i;
b[tool_0_cnt] = tool_0_cnt;
}
}
for(int i = 0;i < 20;i ++) ll[1<<i] = n+1;
scanf("%s",ss + 1);
for(int i = 1;i <= n;i ++) a[i] = pos[ss[i]];
int ALL = 0;
for(int i = 1;i <= n;i ++) {
ll[1<<a[i]] = min(ll[1<<a[i]],(short)i);
rr[1<<a[i]] = i; cnt[1<<a[i]] ++;
ALL |= (1<<a[i]);
}
sort(b,b + 20,cmp);
int tp = 1<<20;
for(int i = 1;i < tp;i ++) {
if(i-lowbit(i)) {
ll[i] = min(ll[i-lowbit(i)],ll[lowbit(i)]);
rr[i] = max(rr[i-lowbit(i)],rr[lowbit(i)]);
cnt[i] = cnt[i-lowbit(i)] + cnt[lowbit(i)];
}
}
dp[0] = 1;
for(int i = 1;i < tp;i ++) {
if((rr[i]-ll[i]+1) * ka <= cnt[i] * kb && (i&ALL) == i) {
if(i == lowbit(i)) {
dp[i] = 1;
}
else {
for(int j = 0;j < 20;j ++) {
if(i & (1<<j)) dp[i] |= dp[i^(1<<j)];
}
}
}
if((i&ALL) == i) {
if(i ^ lowbit(i)) {
int S = 0;
for(int j = 0;j < 20;j ++) {
S = (S|(1<<b[j])) & i;
if(S != i && S) dp[i] |= dp[i^S] & dp[S];
}
}
}
}
int as = 0;
for(int i = 0;i < 20;i ++) if(dp[ALL^(1<<i)]) as ++;
printf("%d",as);
for(int i = 0;i < 20;i ++) if(dp[ALL^(1<<i)]) printf(" %c",denote[i]);
ENDL;
return 0;
}

CF1450G. Communism(状压DP)的更多相关文章

  1. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  2. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  3. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  4. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  5. 【BZOJ2073】[POI2004]PRZ 状压DP

    [BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...

  6. bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

    数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...

  7. HDU 1074 Doing Homework (状压dp)

    题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...

  8. 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP

    [BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...

  9. 【BZOJ1725】[Usaco2006 Nov]Corn Fields牧场的安排 状压DP

    [BZOJ1725][Usaco2006 Nov]Corn Fields牧场的安排 Description Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M< ...

  10. 【BZOJ1087】 [SCOI2005]互不侵犯King 状压DP

    经典状压DP. f[i][j][k]=sum(f[i-1][j-cnt[k]][k]); cnt[i]放置情况为i时的国王数量 前I行放置情况为k时国王数量为J #include <iostre ...

随机推荐

  1. 分享一款自带工作流引擎的NodeJS全栈框架,接单快手、创业神器

    CabloyJS是什么 CabloyJS是一款自带工作流引擎的Node.js全栈框架, 接单快手.创业神器, 基于koa + egg + vue + framework7 + mysql 在线演示 场 ...

  2. LOJ数列分块 9 题解

    \(1.\) 题意 给定一个长度 \(n\) 序列,每次查询区间 \(l, r\) 的众数. \(2.\) 思路 如果边界是 \([l,r]\),\(l\) 在第 \(a\) 块,\(r\) 在第 \ ...

  3. SpringBoot整合RabbitMQ实战附加死信交换机

    前言 使用springboot,实现以下功能,有两个队列1.2,往里面发送消息,如果处理失败发生异常,可以重试3次,重试3次均失败,那么就将消息发送到死信队列进行统一处理,例如记录数据库.报警等 环境 ...

  4. React关于constructor与super(props)之间的相爱相杀

    我们先把菜鸟教程的一段代码拿过来分析一下.下面这段代码是用了将生命周期方法添加到类中实现时钟效果. // 将生命周期方法添加到类中 class Clock extends React.Componen ...

  5. Java Web servlet 详解

    执行原理 当服务器接收到客户端浏览器的访问时,会解析请求的URL路径,获取访问的Servlet的资源路径 查找web.xml文件,看是否有对应的<url-pattern>标签体内容 如果有 ...

  6. 告别单调,Django后台主页改造 - 使用AdminLTE组件

    前言 之前我做了个Django的项目,为了让管理后台更加美观,我对Django(应该说是SimpleUI的)默认的Admin后台主页进行改造,具体可以看这篇文章:项目完成 - 基于Django3.x版 ...

  7. 如何用Fiddler对APP进行网络测试

    什么是Fiddler Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的"进出"Fiddler的数据(指co ...

  8. DTCC 干货分享:Real Time DaaS - 面向TP+AP业务的数据平台架构

      2021年10月20日,Tapdata 创始人唐建法(TJ)受邀出席 DTCC 2021(中国数据库技术大会),并在企业数据中台设计与实践专场上,发表主旨演讲"Real Time Daa ...

  9. Java 浅做计算器

    package www.nihao; import java.util.Scanner; public class counter { public static void main(String[] ...

  10. 安卓fastboot刷机、刷magisk、aidlux备忘

    环境就不多说了,网上一堆教程,我只在这边简单记录一下,以小米手机为例 刷机 解锁bootloader PC上配置好adb.fastboot,也就是platform-tools工具包加入系统变量,在命令 ...