(线段树 + 思维)or 动态dp

[Problem - F - Codeforces](https://codeforces.com/contest/1743/problem/E)

题意

数轴上有 \(n\) 个线段 \([l,r]\;(0<=l<=r<=3*10^5)\) ,表示有一个集合 \(s_i\) 为 \([l,r]\)

有三种集合运算,交、并、异或(两个集合异或 = 并 - 交)

\(S=s_i\;op\;s_2\;op\;...\;op\;s_n\) ,对于 \(n-1\) 个 op 的选择,有 \(3^{n-1}\) 种,求这 \(3^{n-1}\) 个 S 的大小之和

思路1

  1. 单独考虑一个元素 \(x\), 设 \(a\) 为包含 x 的一个集合,\(b\) 为不包含 \(x\) 的一个集合

  2. 关键是发现如下性质:

    1. 两个 b 搞不出来 x
    2. a 交,并 a 可以保留 x,有 2 种
    3. a 并,异或 b 可以保留 x,有 2 种
  3. 因此若最终想保留 x,则需要找到最后一个包含 x 的集合的下标 last (用线段树来维护单点最大值和区间赋值)

    前 last - 2 个操作无所谓;后面的 n - last + 1 个操作只有 2 种选择才能保留 x

    因此保留 x 的方案数为 \(3^{last-2}*2^{n-last+1}\) 个

思路2

  1. 同样单独考虑一个元素 x

  2. 设 \(f[i][0/1]\) 表示前 i 个集合操作完后,x 是否在当前集合中的方案数

  3. 当 x 在 \(s_i\) 中时

    1. \(f[i][0]=f[i-1][0]+f[i-1][1]\)
    2. \(f[i][1]=2*f[i-1][0]+2*f[i-1][1]\)

    当 x 不在 \(s_i\) 中时

    1. \(f[i][0]=3*f[i-1][0]+f[i-1][1]\)
    2. \(f[i][1]=2*f[i-1][1]\)
  4. 但这样转移的复杂度为 \(O(n*3e5)\)

  5. 由于每个集合都是一个区间,可以用线段树来优化,可以对每个区间中所有数整体来转移

  6. 上述转移可写成矩阵的形式:

    1. x 在 \(s_i\) 中时
    \[\begin{bmatrix}
    f[i][0]\\
    f[i][1]
    \end{bmatrix}=
    \begin{bmatrix}
    1&1\\
    2&2
    \end{bmatrix}*
    \begin{bmatrix}
    f[i-1][0]\\
    f[i-1][1]
    \end{bmatrix}
    \]
    1. x 不在 \(s_i\) 中时
      \[\begin{bmatrix}
      f[i][0]\\
      f[i][1]
      \end{bmatrix}=
      \begin{bmatrix}
      3&1\\
      2&0
      \end{bmatrix}*
      \begin{bmatrix}
      f[i-1][0]\\
      f[i-1][1]
      \end{bmatrix}
      \]
  7. 可用线段树对一个区间整体乘上一个矩阵

代码1

#include <bits/stdc++.h>
using namespace std;
#define endl "\n" typedef long long ll;
typedef pair<int, int> PII; const int N = 3e5 + 10;
const int mod = 998244353;
int n;
struct SegmentTree {
#define ls u << 1
#define rs u << 1 | 1
struct T {
int l, r;
ll v;
ll add;
}tr[N << 2];
void pushup(int u) {
tr[u].v = max(tr[ls].v, tr[rs].v);
}
void update(T& rt, int add) {
rt.add = add, rt.v = add;
}
void pushdown(int u) {
if (tr[u].add) {
update(tr[ls], tr[u].add);
update(tr[rs], tr[u].add);
tr[u].add = 0;
}
}
void build(int u, int l, int r) {
tr[u].l = l, tr[u].r = r, tr[u].v = tr[u].add = 0;
if (tr[u].l == tr[u].r) {
return ;
}
int mid = (tr[u].l + tr[u].r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(u);
return ;
}
void modify(int u, int l, int r, int v) {
if (tr[u].l >= l && tr[u].r <= r) {
update(tr[u], v);
return ;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) modify(ls, l, r, v);
if (r > mid) modify(rs, l, r, v);
pushup(u);
return ;
}
int query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) {
return tr[u].v;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
int res = 0;
if (l <= mid) res = query(ls, l, r);
if (r > mid) res = max(res, query(rs, l, r));
return res;
}
}tr; ll qmi(ll a, ll b)
{
ll ans = 1;
while(b)
{
if (b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
} int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
tr.build(1, 0, N - 10);
for (int i = 1; i <= n; i++)
{
int l, r;
cin >> l >> r;
tr.modify(1, l, r, i);
}
ll ans = 0;
for (int i = 0; i <= N - 10; i++)
{
int last = tr.query(1, i, i);
if (last == 0)
continue;
int a = max(0, last - 2);
int b = n - 1 - a;
ans += qmi(3, a) * qmi(2, b) % mod;
ans %= mod;
}
cout << ans << endl;
return 0;
}

Educational Codeforces Round 137 (Rated for Div. 2) - F. Intersection and Union的更多相关文章

  1. Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings

    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings 题目连接: http://cod ...

  2. Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块

    Educational Codeforces Round 71 (Rated for Div. 2)-F. Remainder Problem-技巧分块 [Problem Description] ​ ...

  3. Educational Codeforces Round 137 (Rated for Div. 2) A-F

    比赛链接 A 题解 知识点:数学. \(4\) 位密码,由两个不同的数码组成,一共有 \(C_4^2\) 种方案.从 \(10-n\) 个数字选两个,有 \(C_{10-n}^2\) 种方案.结果为 ...

  4. Educational Codeforces Round 50 (Rated for Div. 2) F - Relatively Prime Powers(数学+容斥)

    题目链接:http://codeforces.com/contest/1036/problem/F 题意: 题解:求在[2,n]中,x != a ^ b(b >= 2 即为gcd)的个数,那么实 ...

  5. Educational Codeforces Round 58 (Rated for Div. 2) F dp + 优化(新坑) + 离线处理

    https://codeforces.com/contest/1101/problem/F 题意 有n个城市,m辆卡车,每辆卡车有起点\(s_i\),终点\(f_i\),每公里油耗\(c_i\),可加 ...

  6. Educational Codeforces Round 42 (Rated for Div. 2)F - Simple Cycles Edges

    http://codeforces.com/contest/962/problem/F 求没有被两个及以上的简单环包含的边 解法:双联通求割顶,在bcc中看这是不是一个简单环,是的话把整个bcc的环加 ...

  7. Educational Codeforces Round 41 (Rated for Div. 2)F. k-substrings

    题意比较麻烦略 题解:枚举前缀的中点,二分最远能扩展的地方,lcp来check,然后线段树维护每个点最远被覆盖的地方,然后查询线段树即可 //#pragma GCC optimize(2) //#pr ...

  8. Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)

    题意 给定一棵 \(n\) 个点的带点权树,以 \(1\) 为根, \(m\) 次询问,每次询问给出两个值 \(p, k\) ,求以下值: \(p\) 的子树中距离 \(p \le k\) 的所有点权 ...

  9. Educational Codeforces Round 47 (Rated for Div. 2)F. Dominant Indices 线段树合并

    题意:有一棵树,对于每个点求子树中离他深度最多的深度是多少, 题解:线段树合并快如闪电,每个节点开一个权值线段树,递归时合并即可,然后维护区间最多的是哪个权值,到x的深度就是到根的深度减去x到根的深度 ...

  10. Educational Codeforces Round 56 (Rated for Div. 2) F - Vasya and Array dp好题

    F - Vasya and Array dp[ i ][ j ] 表示用了前 i 个数字并且最后一个数字是 j 的方案数. dp[ i ][ j ] = sumdp [i - 1 ][ j ], 这样 ...

随机推荐

  1. nuxt.js中引入lib-flexible 和 postcss-px2rem 实现pc自适应

    最近一个需要用nuxt框架实现的pc自适应项目,从网上找了很多资料,最终完美实现 一.下载相关插件 npm i lib-flexible -Snpm i px2rem-loader -Dnpm ins ...

  2. 8、IDEA提交代码出现: Fetch failed fatal: Could not read from remote repository

    转载自 第一步.确认Git公钥/密钥是否生成: 1. 首先查看本地是否生成git密钥,一般在C盘home目录下:[C:你自己的home目录\.ssh] 第二步:添加Git密钥: 右键->Git ...

  3. [编程基础] Python对象的浅拷贝与深拷贝笔记

    Python中的赋值语句不创建对象的副本,它们只将名称绑定到对象.对于不可变的对象,这通常没有什么区别.但是对于处理可变对象或可变对象的集合,您可能需要寻找一种方法来创建这些对象的"真实副本 ...

  4. 一文教会你mock(Mockito和PowerMock双剑合璧)

    作者:京东物流 杨建民 1.什么是Mock Mock有模仿.伪造的含义.Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法.mock工具使用 ...

  5. JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来3 —— 本地缓存变身分布式集群缓存,打破本地缓存天花板

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中,我们知晓了如何在项目中通 ...

  6. python进阶之路5之流程控制(垃圾回收机制)

    垃圾回收机制 """ 有一些语言,内存空间的申请和释放都需要程序员自己写代码才可以完成 但是python却不需要 通过垃圾回收机制自动管理 ""&qu ...

  7. printf()和scanf()的*修飾符

    如果你不想預先設置字段的寬度,想通過程序來進行設定,則可以可以使用"*"來進行修飾字段的寬度,前提是在程序中要包含"*"和參數對應的值(比如%*d,那麽參數應該 ...

  8. 最最最常用的Git提交规范以及常用命令总结

    提交规范 为什么要制定提交规范? 便于对提交历史进行追溯,以及快速定位 代码改动的历史更加清晰 格式化的 Commit Message 才可以用于自动化输出 Change log 如何制定提交规范? ...

  9. 迁移学习(ADDA)《Adversarial Discriminative Domain Adaptation》

    论文信息 论文标题:Adversarial Discriminative Domain Adaptation论文作者:Eric Tzeng, Judy Hoffman, Kate Saenko, Tr ...

  10. Python 内置界面开发框架 Tkinter入门篇 乙

    本文大概 1685 个字,阅读需花 6 分钟内容不多, 但也花了一些精力如要交流, 欢迎关注我然后评论区留言 谢谢你的点赞收藏分享 这篇文章属于系列文章<Python 内置界面开发框架 Tkin ...