Solution

标程太暴力惹QAQ 相当于是26棵线段树的说QAQ

不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和。

修改操作就是先查询这个区间1的数量,排序本质上就是把1一起放在这个区间前面或后面,最后查询每个位置,如果为1并且没有被标记过,就标记成当前枚举的字母即可。

将看似复杂的问题转化为了简单的区间修改和查询QAQ

不过需要各种常数优化才能过QAQ

Code

  1. #include<bits/stdc++.h>
  2. #define RG register
  3. using namespace std;
  4.  
  5. int TR[], tag[];
  6.  
  7. char a[];
  8. int s[];
  9.  
  10. inline int read() {
  11. int x = ; char ch = getchar();
  12. while(ch > '' || ch < '') ch = getchar();
  13. while(ch >= '' && ch <= '') {
  14. x = x * + ch - ''; ch = getchar();
  15. }
  16. return x;
  17. }
  18.  
  19. inline void update(int nd) {
  20. TR[nd] = TR[nd << ] + TR[nd << | ];
  21. }
  22.  
  23. inline void push_down(int nd, int l, int r) {
  24. if(~tag[nd]) {
  25. int mid = (l + r) >> ;
  26. TR[nd << ] = tag[nd] * (mid - l + );
  27. TR[nd << | ] = tag[nd] * (r - mid);
  28. tag[nd << ] = tag[nd];
  29. tag[nd << | ] = tag[nd];
  30. tag[nd] = -;
  31. }
  32. }
  33.  
  34. inline void build(int nd, int l, int r) {
  35. tag[nd] = -;
  36. if(l == r) {
  37. TR[nd] = s[l]; return ;
  38. }
  39. int mid = (l + r) >> ;
  40. build(nd << , l, mid);
  41. build(nd << | , mid + , r);
  42. update(nd);
  43. }
  44.  
  45. inline int query(int nd, int l, int r, int L, int R) {
  46. if(TR[nd] == ) return ;
  47. if(L > R) return ;
  48. if(l >= L && r <= R) {
  49. int tmp = TR[nd];
  50. TR[nd] = ; tag[nd] = ;
  51. return tmp;
  52. }
  53. push_down(nd, l, r);
  54. int mid = (l + r) >> ; int ans = ;
  55. if(L <= mid) ans += query(nd << , l, mid, L, R);
  56. if(R > mid) ans += query(nd << | , mid + , r, L, R);
  57. update(nd);
  58. return ans;
  59. }
  60.  
  61. inline void modify(int nd, int l, int r, int L, int R, int d) {
  62. if(L > R) return ;
  63. if(l >= L && r <= R) {
  64. tag[nd] = d;
  65. TR[nd] = (r - l + ) * d;
  66. return ;
  67. }
  68. push_down(nd, l, r);
  69. int mid = (l + r) >> ;
  70. if(L <= mid) modify(nd << , l, mid, L, R, d);
  71. if(R > mid) modify(nd << | , mid + , r, L, R, d);
  72. update(nd);
  73. }
  74.  
  75. int d[];
  76. inline void get(int nd, int l, int r) {
  77. if(l == r) {
  78. d[l] = TR[nd]; return ;
  79. }
  80. push_down(nd, l, r);
  81. int mid = (l + r) >> ;
  82. get(nd << , l, mid); get(nd << | , mid + , r);
  83. }
  84.  
  85. int n, m, l[], r[], x[], color[];
  86. int main() {
  87. freopen("string.in", "r", stdin);
  88. freopen("string.out", "w", stdout);
  89. n = read(), m = read();
  90. scanf("%s", a + );
  91. for(int i = ; i <= m; i ++)
  92. l[i] = read(), r[i] = read(), x[i] = read();
  93. for(RG int i = ; i >= ; i --) {
  94. for(RG int j = ; j <= n; j ++)
  95. if(a[j] >= i + 'a') s[j] = ;
  96. else s[j] = ;
  97. build(, , n);
  98. for(RG int j = ; j <= m; j ++) {
  99. int delta = query(, , n, l[j], r[j]);
  100. if(x[j] == ) {
  101. if(delta > ) modify(, , n, l[j], l[j] + delta - , );
  102. }
  103. else {
  104. if(delta > ) modify(, , n, r[j] - delta + , r[j], );
  105. }
  106. }
  107. get(, , n);
  108. for(RG int j = ; j <= n; j ++) {
  109. if(d[j] && !color[j]) color[j] = i;
  110. }
  111. }
  112. for(int i = ; i <= n; i ++)
  113. printf("%c", color[i] + 'a');
  114. return ;
  115. }

Solution

转移可以说是很难想了QAQ

列上的限制比行上明显要少,所以定义$dp[i][j]$表示当前扫到了第$i$列,当前没有填数的右区间有$j$个时的方案数。这个右区间指$r[k]$在$1~i$范围内的区间,左区间同理。

从前往后有当前放数或不放数两个情况,放数还分左区间放和右区间放。详情看代码吧QAQ

Code

  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. #define mod 998244353
  4. using namespace std;
  5.  
  6. int dp[][];
  7. int l[], r[], n, m, x, y;
  8.  
  9. int main() {
  10. freopen("matrix.in", "r", stdin);
  11. freopen("matrix.out", "w", stdout);
  12. scanf("%d%d", &n, &m);
  13. for(int i = ; i <= n; i ++) scanf("%d%d", &x, &y), l[x] ++, r[y] ++;
  14. dp[][] = ; int tot = , tmp = ;
  15. for(int i = ; i <= m; i ++) {
  16. tmp ++;
  17. tot += r[i];
  18. for(int j = r[i]; j <= tot; j ++)
  19. dp[i][j] = dp[i - ][j - r[i]];
  20. for(int j = ; j <= tot; j ++)
  21. dp[i][j - ] = (dp[i][j - ] + 1ll * dp[i][j] * j % mod) % mod;
  22. for(int j = ; j <= l[i]; j ++) {
  23. for(int k = ; k <= tot; k ++)
  24. dp[i][k] = 1ll * dp[i][k] * max(, tmp - (tot - k)) % mod;
  25. tmp --;
  26. }
  27. }
  28. printf("%d", dp[m][]);
  29. return ;
  30. }

Solution

看到这种位运算就想到$Trie$树啥的,可是怎么建树还有怎么扫都毫无思路啊QAQ

首先还是从式子入手,对手改变一次的那个式子中,当$x<2^{n-1}$时,原式相当于将$x$左移一位,反之相当于将$x$左移一位再加一,具体写一写就知道了。

这就相当于在断点的位置,把$x$的最高位取下来放到最后。

又因为前面总贡献和后面总贡献都是可以预处理出来的前后缀异或和,再加上按位运算,只会影响一位,与其它位无关,所以可以$O(m)$处理出来每个断点的贡献,将所有贡献加入$Trie$数中。

然后考虑怎么走$x$。因为对手想让结果尽量小,所以他一定会尽量让选择的$x$往和$Trie$数上节点相同的地方走。

所以$dfs$遍历trie树时,如果两边儿子都有,那么这一层不管怎么选都不会有贡献,如果有一边的儿子,那么就可以获得另一边的贡献。但是遍历还是只能顺着这边遍历下去,遍历与计算贡献无关。

Code

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. int t[], tot;
  5. int n, m;
  6. int son[][], tail;
  7. int pre[], las[], a[];
  8.  
  9. void add(int x) {
  10. memset(t, , sizeof(t)); tot = ;
  11. while(x) {
  12. t[++tot] = (x & );
  13. x >>= ;
  14. }
  15. int nd = ;
  16. for(int i = n; i >= ; i --) {
  17. if(!son[nd][t[i]]) son[nd][t[i]] = ++ tail;
  18. nd = son[nd][t[i]];
  19. }
  20. }
  21.  
  22. int ans1, ans2;
  23. void dfs(int nd, int val, int depth) {
  24. if(depth == -) {
  25. if(val > ans1) ans1 = val, ans2 = ;
  26. else if(val == ans1) ans2 ++;
  27. return ;
  28. }
  29. if(son[nd][] && son[nd][]) {
  30. dfs(son[nd][], val, depth - );
  31. dfs(son[nd][], val, depth - );
  32. } else if(son[nd][]) dfs(son[nd][], val + ( << depth), depth - );
  33. else if(son[nd][]) dfs(son[nd][], val + ( << depth), depth - );
  34. }
  35.  
  36. int main() {
  37. freopen("big.in", "r", stdin);
  38. freopen("big.out", "w", stdout);
  39. scanf("%d%d", &n, &m);
  40. for(int i = ; i <= m; i ++) scanf("%d", &a[i]), pre[i] = pre[i - ] ^ a[i];
  41. for(int i = m; i >= ; i --) las[i] = las[i + ] ^ a[i];
  42. for(int i = ; i <= m; i ++) {
  43. int now = pre[i] << ;
  44. if( & (now >> n)) now = (now ^ ( << n)) | ;
  45. now ^= las[i + ];
  46. add(now);
  47. }
  48. dfs(, , n - );
  49. printf("%d\n%d", ans1, ans2);
  50. return ;
  51. }

【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】的更多相关文章

  1. 【10.5校内测试】【DP】【概率】

    转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容 ...

  2. luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树

    LINK:字符串树 先说比较简单的正解.由于我没有从最简单的考虑答案的角度思考 所以... 下次还需要把所有角度都考察到. 求x~y的答案 考虑 求x~根+y~根-2*lca~根的答案. 那么问题变成 ...

  3. 【10.4校内测试】【轮廓线DP】【中国剩余定理】【Trie树+博弈】

    考场上几乎是一看就看出来轮廓线叻...可是调了两个小时打死也过不了手出样例!std发下来一对,特判对的啊,转移对的啊,$dp$数组竟然没有取max!!! 某位考生当场死亡. 结果下午又请了诸位dala ...

  4. 【状压dp】Trie 树 @中山纪念中学20170304

    目录 Trie 树 PROBLEM 题目描述 输入 输出 样例输入 样例输出 SOLUTION CODE Trie 树 PROBLEM 题目描述 字母(Trie)树是一个表示一个字符串集合中所有字符串 ...

  5. BZOJ4477[Jsoi2015]字符串树——可持久化trie树

    题目描述 萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字符串树.字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样子.[问题描述]字符串树本质上还是一棵树,即N个节点N ...

  6. 【BZOJ-4212】神牛的养成计划 Trie树 + 可持久化Trie树

    4212: 神牛的养成计划 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 136  Solved: 27[Submit][Status][Discus ...

  7. 【BZOJ4212】神牛的养成计划 Trie树+可持久化Trie树

    [BZOJ4212]神牛的养成计划 Description Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变 ...

  8. 4.24 省选模拟赛 欧珀瑞特 主席树 可持久化trie树

    很容易的一道题目.大概.不过我空间计算失误MLE了 我草草的计算了一下没想到GG了. 关键的是 我学了一个dalao的空间回收的方法 但是弄巧成拙了. 题目没有明确指出 在任意时刻数组长度为有限制什么 ...

  9. 【10.31校内测试】【组合数学】【记忆化搜索/DP】【多起点多终点二进制拆位Spfa】

    Solution 注意取模!!! Code #include<bits/stdc++.h> #define mod 1000000007 #define LL long long usin ...

随机推荐

  1. linux音频alsa-uda134x驱动文档阅读之一转自http://blog.csdn.net/wantianpei/article/details/7817293

    前言 目前,linux系统常用的音频驱动有两种形式:alsa oss alsa:现在是linux下音频驱动的主要形式,与简单的oss兼容.oss:过去的形式而我们板子上的uda1341用的就是alsa ...

  2. 数据库-mysql数据库和表操作

    一:数据库查询增加删除 1)mysql数据库查询:show databases MariaDB [mysql]> show databases; +--------------------+ | ...

  3. manacher模板

    转自:http://blog.csdn.net/zzkksunboy/article/details/72600679 作用 线性时间解决最长回文子串问题. 思想 Manacher充分利用了回文的性质 ...

  4. 【笔记】Python简明教程

    Python简明教程,此资源位于http://woodpecker.org.cn/abyteofpython_cn/chinese/ s=u'中文字符' #u表示unicode,使用u之后能正常显示中 ...

  5. Ubuntu 17.10开启 root 登陆

    使用过 Ubuntu 的人都知道,Ubuntu 默认是不能以 root 登陆的,但是我们是不是就完全不能使用 root 进行登陆了呢?当然不是,只是我们需要做一些设置.而 Ubuntu 17.10 和 ...

  6. 浅谈DDD

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  7. hdu 1085 有num1个 1 ,num2个 2 ,num3个 5 (母函数)

    有num1个 1 ,num2个 2 ,num3个 5问它们不能组成的最小正整数是谁 样例的母函数 (1+X)(1+X2)(1+X5+X10+X15)展开后 X4的系数为0 Sample Input1 ...

  8. Codeforces 429C Guess the Tree(状压DP+贪心)

    吐槽:这道题真心坑...做了一整天,我太蒻了... 题意 构造一棵 $ n $ 个节点的树,要求满足以下条件: 每个非叶子节点至少包含2个儿子: 以节点 $ i $ 为根的子树中必须包含 $ c_i ...

  9. bzoj 2756

    2756 思路: 二分讨论,网络流检验: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e16 #defin ...

  10. 【POJ】1286.Necklace of Beads

    题解 群论,我们只要找出所有的置换群的所有循环节 具体可参照算法艺术与信息学竞赛 旋转的置换有n个,每一个的循环节个数是gcd(N,i),i的范围是0到N - 1 翻转,对于奇数来说固定一个点,然后剩 ...