【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】
Solution
标程太暴力惹QAQ 相当于是26棵线段树的说QAQ
不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和。
修改操作就是先查询这个区间1的数量,排序本质上就是把1一起放在这个区间前面或后面,最后查询每个位置,如果为1并且没有被标记过,就标记成当前枚举的字母即可。
将看似复杂的问题转化为了简单的区间修改和查询QAQ
不过需要各种常数优化才能过QAQ
Code
- #include<bits/stdc++.h>
- #define RG register
- using namespace std;
- int TR[], tag[];
- char a[];
- int s[];
- inline int read() {
- int x = ; char ch = getchar();
- while(ch > '' || ch < '') ch = getchar();
- while(ch >= '' && ch <= '') {
- x = x * + ch - ''; ch = getchar();
- }
- return x;
- }
- inline void update(int nd) {
- TR[nd] = TR[nd << ] + TR[nd << | ];
- }
- inline void push_down(int nd, int l, int r) {
- if(~tag[nd]) {
- int mid = (l + r) >> ;
- TR[nd << ] = tag[nd] * (mid - l + );
- TR[nd << | ] = tag[nd] * (r - mid);
- tag[nd << ] = tag[nd];
- tag[nd << | ] = tag[nd];
- tag[nd] = -;
- }
- }
- inline void build(int nd, int l, int r) {
- tag[nd] = -;
- if(l == r) {
- TR[nd] = s[l]; return ;
- }
- int mid = (l + r) >> ;
- build(nd << , l, mid);
- build(nd << | , mid + , r);
- update(nd);
- }
- inline int query(int nd, int l, int r, int L, int R) {
- if(TR[nd] == ) return ;
- if(L > R) return ;
- if(l >= L && r <= R) {
- int tmp = TR[nd];
- TR[nd] = ; tag[nd] = ;
- return tmp;
- }
- push_down(nd, l, r);
- int mid = (l + r) >> ; int ans = ;
- if(L <= mid) ans += query(nd << , l, mid, L, R);
- if(R > mid) ans += query(nd << | , mid + , r, L, R);
- update(nd);
- return ans;
- }
- inline void modify(int nd, int l, int r, int L, int R, int d) {
- if(L > R) return ;
- if(l >= L && r <= R) {
- tag[nd] = d;
- TR[nd] = (r - l + ) * d;
- return ;
- }
- push_down(nd, l, r);
- int mid = (l + r) >> ;
- if(L <= mid) modify(nd << , l, mid, L, R, d);
- if(R > mid) modify(nd << | , mid + , r, L, R, d);
- update(nd);
- }
- int d[];
- inline void get(int nd, int l, int r) {
- if(l == r) {
- d[l] = TR[nd]; return ;
- }
- push_down(nd, l, r);
- int mid = (l + r) >> ;
- get(nd << , l, mid); get(nd << | , mid + , r);
- }
- int n, m, l[], r[], x[], color[];
- int main() {
- freopen("string.in", "r", stdin);
- freopen("string.out", "w", stdout);
- n = read(), m = read();
- scanf("%s", a + );
- for(int i = ; i <= m; i ++)
- l[i] = read(), r[i] = read(), x[i] = read();
- for(RG int i = ; i >= ; i --) {
- for(RG int j = ; j <= n; j ++)
- if(a[j] >= i + 'a') s[j] = ;
- else s[j] = ;
- build(, , n);
- for(RG int j = ; j <= m; j ++) {
- int delta = query(, , n, l[j], r[j]);
- if(x[j] == ) {
- if(delta > ) modify(, , n, l[j], l[j] + delta - , );
- }
- else {
- if(delta > ) modify(, , n, r[j] - delta + , r[j], );
- }
- }
- get(, , n);
- for(RG int j = ; j <= n; j ++) {
- if(d[j] && !color[j]) color[j] = i;
- }
- }
- for(int i = ; i <= n; i ++)
- printf("%c", color[i] + 'a');
- return ;
- }
Solution
转移可以说是很难想了QAQ
列上的限制比行上明显要少,所以定义$dp[i][j]$表示当前扫到了第$i$列,当前没有填数的右区间有$j$个时的方案数。这个右区间指$r[k]$在$1~i$范围内的区间,左区间同理。
从前往后有当前放数或不放数两个情况,放数还分左区间放和右区间放。详情看代码吧QAQ
Code
- #include<bits/stdc++.h>
- #define LL long long
- #define mod 998244353
- using namespace std;
- int dp[][];
- int l[], r[], n, m, x, y;
- int main() {
- freopen("matrix.in", "r", stdin);
- freopen("matrix.out", "w", stdout);
- scanf("%d%d", &n, &m);
- for(int i = ; i <= n; i ++) scanf("%d%d", &x, &y), l[x] ++, r[y] ++;
- dp[][] = ; int tot = , tmp = ;
- for(int i = ; i <= m; i ++) {
- tmp ++;
- tot += r[i];
- for(int j = r[i]; j <= tot; j ++)
- dp[i][j] = dp[i - ][j - r[i]];
- for(int j = ; j <= tot; j ++)
- dp[i][j - ] = (dp[i][j - ] + 1ll * dp[i][j] * j % mod) % mod;
- for(int j = ; j <= l[i]; j ++) {
- for(int k = ; k <= tot; k ++)
- dp[i][k] = 1ll * dp[i][k] * max(, tmp - (tot - k)) % mod;
- tmp --;
- }
- }
- printf("%d", dp[m][]);
- return ;
- }
Solution
看到这种位运算就想到$Trie$树啥的,可是怎么建树还有怎么扫都毫无思路啊QAQ
首先还是从式子入手,对手改变一次的那个式子中,当$x<2^{n-1}$时,原式相当于将$x$左移一位,反之相当于将$x$左移一位再加一,具体写一写就知道了。
这就相当于在断点的位置,把$x$的最高位取下来放到最后。
又因为前面总贡献和后面总贡献都是可以预处理出来的前后缀异或和,再加上按位运算,只会影响一位,与其它位无关,所以可以$O(m)$处理出来每个断点的贡献,将所有贡献加入$Trie$数中。
然后考虑怎么走$x$。因为对手想让结果尽量小,所以他一定会尽量让选择的$x$往和$Trie$数上节点相同的地方走。
所以$dfs$遍历trie树时,如果两边儿子都有,那么这一层不管怎么选都不会有贡献,如果有一边的儿子,那么就可以获得另一边的贡献。但是遍历还是只能顺着这边遍历下去,遍历与计算贡献无关。
Code
- #include<bits/stdc++.h>
- using namespace std;
- int t[], tot;
- int n, m;
- int son[][], tail;
- int pre[], las[], a[];
- void add(int x) {
- memset(t, , sizeof(t)); tot = ;
- while(x) {
- t[++tot] = (x & );
- x >>= ;
- }
- int nd = ;
- for(int i = n; i >= ; i --) {
- if(!son[nd][t[i]]) son[nd][t[i]] = ++ tail;
- nd = son[nd][t[i]];
- }
- }
- int ans1, ans2;
- void dfs(int nd, int val, int depth) {
- if(depth == -) {
- if(val > ans1) ans1 = val, ans2 = ;
- else if(val == ans1) ans2 ++;
- return ;
- }
- if(son[nd][] && son[nd][]) {
- dfs(son[nd][], val, depth - );
- dfs(son[nd][], val, depth - );
- } else if(son[nd][]) dfs(son[nd][], val + ( << depth), depth - );
- else if(son[nd][]) dfs(son[nd][], val + ( << depth), depth - );
- }
- int main() {
- freopen("big.in", "r", stdin);
- freopen("big.out", "w", stdout);
- scanf("%d%d", &n, &m);
- for(int i = ; i <= m; i ++) scanf("%d", &a[i]), pre[i] = pre[i - ] ^ a[i];
- for(int i = m; i >= ; i --) las[i] = las[i + ] ^ a[i];
- for(int i = ; i <= m; i ++) {
- int now = pre[i] << ;
- if( & (now >> n)) now = (now ^ ( << n)) | ;
- now ^= las[i + ];
- add(now);
- }
- dfs(, , n - );
- printf("%d\n%d", ans1, ans2);
- return ;
- }
【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】的更多相关文章
- 【10.5校内测试】【DP】【概率】
转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容 ...
- luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树
LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...
- 【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】
考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!! 某位考生当场死亡. 结果下午又请了诸位dala ...
- 【状压dp】Trie 树 @中山纪念中学20170304
目录 Trie 树 PROBLEM 题目描述 输入 输出 样例输入 样例输出 SOLUTION CODE Trie 树 PROBLEM 题目描述 字母(Trie)树是一个表示一个字符串集合中所有字符串 ...
- BZOJ4477[Jsoi2015]字符串树——可持久化trie树
题目描述 萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字符串树.字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样子.[问题描述]字符串树本质上还是一棵树,即N个节点N ...
- 【BZOJ-4212】神牛的养成计划 Trie树 + 可持久化Trie树
4212: 神牛的养成计划 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 136 Solved: 27[Submit][Status][Discus ...
- 【BZOJ4212】神牛的养成计划 Trie树+可持久化Trie树
[BZOJ4212]神牛的养成计划 Description Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变 ...
- 4.24 省选模拟赛 欧珀瑞特 主席树 可持久化trie树
很容易的一道题目.大概.不过我空间计算失误MLE了 我草草的计算了一下没想到GG了. 关键的是 我学了一个dalao的空间回收的方法 但是弄巧成拙了. 题目没有明确指出 在任意时刻数组长度为有限制什么 ...
- 【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】
Solution 注意取模!!! Code #include<bits/stdc++.h> #define mod 1000000007 #define LL long long usin ...
随机推荐
- 【比赛游记】THUWC2019酱油记
往期回顾:THUSC2018酱油记 day 0 早上 7 点的动车,不知道是从哪儿到哪儿的(雾),只知道从福建到广东 233333 一个值得思考的问题:福建人会不会被广东人吃啊? 动车上玩空洞骑士,可 ...
- ip_local_deliver && ip_local_deliver_finish
当ip包收上来,查路由,发现是发往本地的数据包时,会调用ip_local_deliver函数: ip_local_deliver中对ip分片进行重组,经过LOCAL_IN钩子点,然后调用ip_loca ...
- C# 调用WSDL接口及方法
1.首先需要清楚WSDL的引用地址 如:http://XX.XX.4.146:8089/axis/services/getfileno?wsdl 上述地址的构造为 类名getfileno. 2.在.N ...
- poj1095
题意:给出n,要求输出第n个二叉树,二叉树编号规则如下图所示: 分析:g[i]表示有i个节点的二叉树,有多少种.f[i][j]表示有i个节点,且左子树有j个节点的树有多少种. sumg[i]表示g数组 ...
- eclipse导入/导出项目要注意三个地方
这个三个地方的jdk必须保持一致,不报错
- IntelliJ IDEA 去除IDE自动的参数名 提示功能
- IntelliJ IDEA + Tomcat ;On Upate Action 与 On Frame Deactivation
On Upate Action 与 On Frame Deactivation 这两个选项的设置,依赖于 项目的部署方式 是war包 还是 exploded ,看下面的gif: 这里实在是太灵活了, ...
- CVE-2012-0158基于exp分析
CVE-2012-0158这个洞我之前分析过,漏洞战争这本书里也写过,但是都是用poc分析的,我这次找了一个弹计算器的exp来分析,感觉用poc和用exp还是不一样的,从exp分析要比从poc分析更复 ...
- SQL Server中的快捷键
新建查询:Ctrl + N 反撤销:Ctrl + Y 撤销:Ctrl + Z 查找:Ctrl + F 启动调试:Alt + F5 注释:Ctrl + K + C 取消注释:Ctrl + K + U 执 ...
- Bootstrap Paginator分页插件使用示例
最近做的asp.netMVC项目中需要对数据列表进行分类,这个本来就是基于bootstrap开发的后台,因此也就想着bootstrap是否有分页插件呢,或者说是基于jquery支持的分页功能,这样整体 ...