写在前面

为什么要写?因为自己学不明白希望日后能掌握。

大体思路大概是

  1. 设计一个容斥的方案,并使其贡献可以便于计算。
  2. 得出 dp 状态,然后优化以得出答案。

下列所有类似 \([l,r]\) 这样的都是离散的。

1.

\(n\) 个点,每个点有一个能选择的颜色 \(a_i\),左右相邻的点不能同色,求方案数。

如果我们使用容斥的思想,强制 \(k\) 段的颜色相同,这个限制下的方案数对答案的贡献的容斥系数就是 \((-1)^{n-k}\)。这应该是相邻颜色不同的方案数的一个非常平凡的trick。(但是我不会

可以设 \(f_i\) 表示统计到前 \(i\) 个点所容斥的答案和。枚举 \([j,i]\) 这一段强制颜色相等。

\[f_i=-\sum\limits_{j=1}^i f_{j-1}\min\limits_{j\le k\le i}a_i
\]

这个东西可以用单调栈维护一下。

注意到这个东西可以拓展到环上。把 \(a_i\) 最小的位置轮换到最前面,然后你发现 \(f_i\) 其实就是强制了 \([i+1,n]\) 和 \(1\) 的颜色相同的答案。全部加起来就好了。

    s[0] = f[0] = 1; int top = 0;
ll sum = 0;
fo(i, 1, c) {
while(top && b[stc[top]] > b[i])
sum = (sum + (ll)(s[stc[top] - 1] - (stc[top] == 1 ? 0 :
s[stc[top - 1] - 1]) + mod) * (b[i] - b[stc[top]] + mod)) % mod,
--top;
stc[++top] = i;
sum = (sum + (ll)f[i - 1] * b[i]) % mod;
f[i] = mod - sum;
s[i] = (f[i] + s[i - 1]) % mod;
}

2.

\(n\) 个点,一个区间可以覆盖 \([l_i,r_i]\) 这一段,每个区间有一个价值 \(v_i\) ,定义一种“覆盖”为每个点至少被一个区间所覆盖的方案,其价值为所有所选区间的价值积,求所有覆盖的价值之和。

考虑强制 \(k\) 个点不被覆盖,那么这种情况对答案的贡献的容斥系数就是 \((-1)^k\)。其贡献就是这些点之间的区间的乘积之和。

这样的话,设 \(f_i\) 表示 \(i\) 点被钦定,枚举 \(j\) 表示上一个钦定点,有

\[f_i=-\sum_{j=1}^{i-1}f_j \prod_{j<l_k\le r_k<i}(v_k+1)
\]

这玩意可以线段树优化!考虑线段树的每一个位置记录的是它作为 \(j\) 造成的贡献,假设现在新加入一个区间 \(k\) ,它能使 \([0,l_k)\) 的位置的贡献发生变化,乘上 \((1+v_k)\)。

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define ll long long
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;
inline void read(int &x) {
x = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
}
const int N = 2e5 + 10, mod = 1e9 + 7;
namespace Seg {
#define ls t << 1
#define rs ls | 1
#define mid ((l + r) >> 1)
int tr[N << 2], pro[N << 2];
inline void mul(int t, int v) {tr[t] = (ll)tr[t] * v % mod, pro[t] = (ll)pro[t] * v % mod;}
inline void push_down(int t) {
if(pro[t] > 1) {
mul(ls, pro[t]), mul(rs, pro[t]);
pro[t] = 1;
}
}
void build(int t, int l, int r) {
pro[t] = 1;
if(l == r) return;
build(ls, l, mid), build(rs, mid + 1, r);
}
void change(int t, int l, int r, int w, int v) {
tr[t] = (tr[t] + v) % mod;
if(l == r) return ;
push_down(t);
w <= mid ? change(ls, l, mid, w, v) : change(rs, mid + 1, r, w, v);
}
void update(int t, int l, int r, int fl, int fr, int v) {
if(fl <= l && r <= fr) return mul(t, v);
push_down(t);
fl <= mid && (update(ls, l, mid, fl, fr, v), 1);
fr > mid && (update(rs, mid + 1, r, fl, fr, v), 1);
tr[t] = (tr[ls] + tr[rs]) % mod;
}
int query(int t, int l, int r, int fl, int fr) {
if(fl <= l && r <= fr) return tr[t];
push_down(t);
int ret = 0;
fl <= mid && (ret = (ret + query(ls, l, mid, fl, fr)) % mod);
fr > mid && (ret = (ret + query(rs, mid + 1, r, fl, fr)) % mod);
return ret;
}
}
struct Op {
int l, r, v;
}p[N];
vector<int> q[N];
int n, m, f[N];
int main() {
freopen("gugugu.in", "r", stdin);
freopen("gugugu.out", "w", stdout);
read(n), read(m);
fo(i, 1, m) read(p[i].l), read(p[i].r), read(p[i].v), q[p[i].r].push_back(i);
Seg::build(1, 0, n);
Seg::change(1, 0, n, 0, 1);
fo(i, 1, n + 1) {
Seg::change(1, 0, n, i, f[i] = mod - Seg::query(1, 0, n, 0, i - 1));
for(auto k : q[i])
Seg::update(1, 0, n, 0, p[k].l - 1, (p[k].v + 1) % mod);
}
printf("%d\n", mod - f[n + 1]);
return 0;
}

To be continued..

关于一类容斥原理设计 dp 状态的探讨的更多相关文章

  1. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

  2. [提升性选讲] 树形DP进阶:一类非线性的树形DP问题(例题 BZOJ4403 BZOJ3167)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7337179.html 树形DP是一种在树上进行的DP相对比较难的DP题型.由于状态的定义多种多样,因此解法也五 ...

  3. dp状态压缩

    dp状态压缩 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了.难点在于以下几个方面:状 ...

  4. HDU 1074 Doing Homework (dp+状态压缩)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074 题目大意:学生要完成各科作业, 给出各科老师给出交作业的期限和学生完成该科所需时间, 如果逾期一 ...

  5. hdu_4352_XHXJ's LIS(数位DP+状态压缩)

    题目连接:hdu_4352_XHXJ's LIS 题意:这题花大篇篇幅来介绍电子科大的一个传奇学姐,最后几句话才是题意,这题意思就是给你一个LL范围内的区间,问你在这个区间内最长递增子序列长度恰为K的 ...

  6. hdu 4352 数位dp + 状态压缩

    XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. HDU 1074 Doing Homework(DP状态压缩)

    题意:有n门功课需要完成,每一门功课都有时间期限以及你完成所需要的时间,如果完成的时间超出时间期限多少单位,就会被减多少学分,问以怎样的功课完成顺序,会使减掉的学分最少,有多个解时,输出功课名字典序最 ...

  8. 【bzoj1076】[SCOI2008]奖励关 期望dp+状态压缩dp

    题目描述 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再 ...

  9. hdu4336 Card Collector(概率DP,状态压缩)

    In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, fo ...

随机推荐

  1. Linux学习 - 压缩解压命令

    一." .gz "压缩文件 1 压缩语法 gzip  [文件] 2 解压语法 gunzip  [压缩文件] 3 注 gzip只能压缩文件 gzip不保留原文件 二." . ...

  2. 接口测试 python+PyCharm 环境搭建

    1.配置Python环境变量 a:我的电脑->属性->高级系统设置->环境变量->系统变量中的PATH变量. 变量名:PATH      修改变量值为:;C:\Python27 ...

  3. 通过spring-data-redis操作Redis

    一.操作String类型数据 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring/ ...

  4. 【C#】【假条生成系统】【单位剖析】如何判断在文本框输入了几个人名?

    我们规定,人名和人名之间使用顿号隔开 那么, 1个人,就是0个顿号 2个人,就是1个顿号 3个人,就是2个顿号 -- 所以我们可以判断文本框中顿号的出现次数. 出现0次,则为1人,出1次,则为两人. ...

  5. [特征工程] encoding

    参考:An Overview of Encoding Techniques | Kaggle Method 1: Label encoding  给每个类别以一个数字label,作为分类.将类别映射到 ...

  6. TV盒子 android 4.4安装kodi 和 安装jellyfin插件连接到 jellyfin服务器

    很多IPTV盒子系统都是android 4.4的,无法安装新版kodi, 最高只能安装到改版的kodi, 版本是17.1,jellyfin插件也只能安装到0.5.8 首先下载kodi和jellyfin ...

  7. 企业级BI是自研还是采购?

    企业级BI是自研还是采购? 上一篇<企业级BI为什么这么难做?>,谈到了企业级BI项目所具有的特殊背景,以及在"破局"方面的一点思考,其中谈论的焦点主要是在IT开发项目 ...

  8. CentOS6设置开机自启动

    1.把开机启动脚本(mysqld)copy到文件夹/etc/init.d 或 /etc/rc.d/init.d 中 2.将启动程序的命令添加到 /etc/rc.d/rc.local 文件中,比如: # ...

  9. SQLserver 2014使用Convert()函数获取时间

    select convert(char(100),GetDate(),120) as Date 第3个参数就是用来设置日期类型数据的显示样式的,下面介绍几种样式的参数 SELECT CONVERT(v ...

  10. 甘特图中与任务有关的操作(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 任务建好了不是马上就没事了,后面还有各种事,比如像我这种粗心的,冷不丁就会冒出个"通假字"什么的,难道 ...