codeforces 938F(dp+高维前缀和)

题意:

  给一个长度为n的字符串,定义$k=\floor{log_2 n}$

  一共k轮操作,第i次操作要删除当前字符串恰好长度为$2^{i-1}$的子串

  问最后剩余的字符串字典序最小是多少?

分析:

  首先很容易得到一个性质,那就是删除的那些串是可以不交叉的
  很容易想到一个很简单的dp

  dp[i][j]表示考虑原串的前i位,删除状态为j的情况下字典序最小的字符串(注意dp里面保存的是个字符串)

  那么很明显就是个O(n^3logn)的dp,无法通过

  dp里是一个字符串这个东西是很浪费时间而且很不优美的

  根据题解的做法,重新设计状态

  dp[i][j]表示已经确定了最终字符串的前i位,目前删除情况为j的情况下,字典序最小的字符串

  这样设计状态我们会发现一个性质,那就是如果dp[i][j]<dp[i][k],那么dp[i][k]就不起作用了

  所以dp数组可以用bool值来表示该状态是否为当前最小的字符串

  更新状态的话,根据确定位数i和删除位数j就知道那些"1"对应字符串的下一位是多少了,更新新的最小字符串

  然后我们要考虑当前阶段给后面要删除几个数,这里即使要求满足若一个状态的某个子集是真,那么它就是真

  这用一个高维前缀和解决即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=5000;
 4 char s[maxn+5];
 5 bool dp[maxn+5][maxn+5];
 6 int n,l,m;
 7 string ans;
 8 int main()
 9 {
10     scanf("%s",s);
11     n=strlen(s);
12     l=0;
13     while((1<<(l+1))<=n) ++l;
14     m=1<<l;
15     for(int j=0;j<m;++j)
16     dp[0][j]=1;
17     for(int i=1;i<=n-m+1;++i)
18     {
19         for(int j=0;j<m;++j) dp[i][j]=dp[i-1][j];
20         char mi=‘z‘;
21         for(int j=0;j<m;++j)
22             if(dp[i-1][j]) mi=min(mi,s[i-1+j]);
23         for(int j=0;j<m;++j)
24             if(dp[i][j]&&s[i-1+j]!=mi) dp[i][j]=0;
25
26         for(int j=0;j<m;++j)
27             for(int k=0;k<l;++k)
28                 if(j&(1<<k)) dp[i][j]|=dp[i][j^(1<<k)];
29         ans=ans+mi;
30
31     }
32     cout<<ans<<endl;
33 }

原文地址:https://www.cnblogs.com/wmrv587/p/8531452.html

时间: 2024-08-25 00:10:29

codeforces 938F(dp+高维前缀和)的相关文章

Codeforces 449D:Jzzhu and Numbers(高维前缀和)

[题目链接] http://codeforces.com/problemset/problem/449/D [题目大意] 给出一些数字,问其选出一些数字作or为0的方案数有多少 [题解] 题目等价于给出一些集合,问其交集为空集的方案数, 我们先求交集为S的方案数,记为dp[S],发现处理起来还是比较麻烦, 我们放缩一下条件,求出交集包含S的方案数,记为dp[S], 我们发现dp[S],是以其为子集的方案的高维前缀和, 我们逆序求高维前缀和即可,之后考虑容斥,求出交集为0的情况, 我们发现这个容斥

4.7-4.9补题+水题+高维前缀和

题目链接:51nod 1718 Cos的多项式  [数学] 题解: 2cosx=2cosx 2cos2x=(2cosx)^2-2 2cos3x=(2cosx)^3-3*(2cosx) 数归证明2cos(nx)能表示成关于2cosx的多项式,设为f(n) f(1)=x,f(2)=x^2-2(其中的x就是2cosx) 假设n=1~k时均成立(k>=3) 当n=k+1时 由cos((k+1)x)=cos(kx)cos(x)-sin(kx)sin(x) cos((k-1)x)=cos(kx)cos(x)

hihocoder1496(高维前缀和)

题意:给定N个数A1, A2, A3, ... AN,小Ho想从中找到两个数Ai和Aj(i ≠ j)使得乘积Ai × Aj × (Ai AND Aj)最大.其中AND是按位与操作. 第一行一个整数N(1<=N<=100,000) 第二行N个整数A1, A2, A3, ... AN (0 <= Ai <2^20) 分析: 尝试枚举and值z,那么问题就变成了找寻最大的x*y,使得x&y==z 把这个要求放宽一点,我们来寻找z是x&y子集的情况(这样肯定不会丢掉整体最优

SPOJ Time Limit Exceeded(高维前缀和)

[题目链接] http://www.spoj.com/problems/TLE/en/ [题目大意] 给出n个数字c,求非负整数序列a,满足a<2^m 并且有a[i]&a[i+1]=0,对于每个a[i],要保证a[i]不是c[i]的倍数, 求这样的a[i]序列的个数 [题解] 我们用dp[i]表示以i为结尾的方案数, 我们发现要满足a[i]&a[i+1]=0,则dp[i]是从上一次结果中所有满足i&j=0的地方转移过来的 i&j=0即i&(~j)=i,即i为~

[2018.6.21集训]走路-分块高维前缀和-Pollard-Rho

题目大意 给一棵树,每个节点有一个权值$val$. 如果两个点$a$和$b$满足$a$为$b$的祖先且$val[b]$为$val[a]$的约数,那么可以从$a$一步跳到$b$. 求从$1$号节点走到各每个节点的路径数. $n \leq 10^5 , val[i] \leq 10^{18},$保证对于任意节点$i$,$val[i]$为$val[1]$的约数. 题解 首先有定理:一个数$n$的约数个数大概是$n^{\frac{1}{3}}$的级别 然后得到有理有据的一个部分分($val[i] \le

codeforces 449D DP+容斥

Jzzhu and Numbers Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-20) Description Jzzhu have n non-negative integers a1, a2, ..., an. We will call a sequence o

高维前缀和

我们经常要用到前缀和. 一维: for(int i=1;i<=n;i++) b[i]=b[i-1]+a[i]; 二维: for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j]; 那如果是三维的呢? for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=1;k<=p;k++) b[i][j][

bzoj 5092 分割序列 —— 高维前缀和

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5092 首先,处理出异或前缀和 s[i],i 位置的答案就是 s[j] + s[j]^s[i],j <= i 异或的套路是按位考虑,但是这里有加法...怎么考虑进位? 所以就不能考虑答案的这一位是什么,而应该考虑在这一位上的贡献,那么即使进位了,还是各位算各位的贡献,互相独立: 然后发现,如果 s[i] 在第 k 位上是1,那么 s[j] 的第 k 位无论是0还是1,总体的贡献都是 1<&

bzoj 5092 [Lydsy1711月赛]分割序列——高维前缀和

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5092 套路地弄一个前缀异或和,就变成 f[ i ]=max_{j=0}^{i} { s[ j ] + (s[ i ]^s[ j ]) }.再套路地考虑按位贪心. 然后看了题解.按位贪心不是确定 f[ i ] 的这一位是0还是1,而是确定这一位是否给答案贡献 bin[ j ] ! 按位考虑,自己这一位如果是1,则 j 不管取在哪,都只有一种情况,就是向答案贡献 bin[ j ]: 自己这一位