ZR1153
ZR1153
首先我们可以发现一个比较简单的容斥做法
直接暴力枚举\(2^m\)个限制强制不合法,算贡献
注意如果两个限制冲突那么答案为0
直接暴力差分就好了
这样就有了快乐的\(30\)分了
接下来考虑对容斥进行DP
把所有点区间按照右端点排序,如果出来两个颜色相同的区间一个包含了另外一个,那么大区间是没有用的,因为小区间满足条件大区间一定满足
我们设\(f_{i}\)表示满足第\(i\)个限制的带容斥系数的方案数
那么转移我们就枚举上一个没有交的区间
\]
其中\(g_x\)表示\(1-x\)位置满足\(1-x\)的所有容斥之后的限制的前缀和
也就是说
\]
就是看看第\(i\)位置上的限制满足还是不满足综合考虑的前缀和
继续回到求\(f_i\)的式子
既然\(i\)的这个限制要容斥,那么强制他不被满足,前面就是对所有和他没有交的限制求一个总的容斥
后面算有交的部分的贡献,必须满足和当前限制的颜色相同,
我们排序之后,有交的集合是一个区间,我们二分找到对应位置维护前缀和即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#include<set>
#include<map>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 4e5 + 3;
const LL mod = 998244353;
struct seg{
int li,ri;
int xi;
}a[N],b[N];
vector <pii> co[N];
vector <LL> h[N];
LL f[N],g[N];
int n,m,s,cnt;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline bool cmp(seg x,seg y){
return x.ri < y.ri || (x.ri == y.li && x.li > y.li);
}
inline LL find(int x,int rr){
// printf("%d %d\n",x,rr);
int l = 0,r = h[x].size() - 1,ans = -1;
if(r < 0) return 0;
while(l <= r){
int mid = (l + r) >> 1;
if(co[x][mid].se < rr) l = mid + 1,ans = mid;
else r = mid - 1;
}
// printf("%d %d %d %lld\n",l,r,ans,ans == -1 ? h[x].back() : h[x].back() - h[x][ans]);
return ans == -1 ? h[x].back() : h[x].back() - h[x][ans];
}
inline LL mo(LL x){
if(x >= mod) x-= mod;
return x;
}
int main(){
n = read(),m = read(),s = read();
for(int i = 1;i <= m;++i){
a[i].li = read();
a[i].ri = read();
a[i].xi = read();
}
sort(a + 1,a + m + 1,cmp);
for(int i = 1;i <= m;++i){
bool flag = 0;
if(!co[a[i].xi].size()) co[a[i].xi].push_back(mk(a[i].li,a[i].ri));
else{
pii x = co[a[i].xi].back();
if(x.fi >= a[i].li && x.se <= a[i].ri) flag = 1;
else co[a[i].xi].push_back(mk(a[i].li,a[i].ri));
}
if(!flag) b[++cnt] = a[i];
}
m = cnt;
memcpy(a,b,sizeof(a));
// puts("new::");
// for(int i = 1;i <= m;++i) cerr << a[i].li << " " << a[i].ri << " " << a[i].xi << endl;
// puts("next::");
int now = 1;
f[0] = g[0] = 1;
for(int i = 1;i <= m;++i){
// cerr << "dsdas::"<< a[i].li << " " << a[i].ri << " " << a[i].xi << endl;
for(;now < a[i].ri;now++) g[now] = (g[now] + g[now - 1] * s) % mod;
f[i] = (-g[a[i].li - 1] + mod);
f[i] -= find(a[i].xi,a[i].li);
if(f[i] < 0) f[i] += mod;
LL gg = h[a[i].xi].empty() ? 0 : h[a[i].xi].back();
h[a[i].xi].push_back(mo(gg + f[i]));
g[a[i].ri] = mo(g[a[i].ri] + f[i]);
}
for(;now <= n;++now) g[now] = (g[now] + g[now - 1] * s) % mod;
printf("%lld\n",g[n]);
return 0;
}
ZR1153的更多相关文章
随机推荐
- 【时光回溯】【JZOJ3567】【GDKOI2014】石油储备计划
题目描述 输入 输出 对于每组数据,输出一个整数,表示达到"平衡"状态所需的最小代价. 样例输入 2 3 6 1 5 1 2 1 2 3 2 5 4 5 4 3 2 1 3 1 1 ...
- 一键制作启动elasticsearch和kibana启动的脚本可执行程序
1.测试环境 测试环境: . windows10专业版 . elasticsearch6.5.4 . kibana6.5.4 2.启动的脚本run.py import os import time i ...
- linux下播放器设计和开发
http://blog.csdn.net/henryjee/article/details/6737392 本文根据DawnLightPlayer的开发经验写成.DawnLithtPlayer是今天3 ...
- Directx11教程(56) 建立一个skydome
原文:Directx11教程(56) 建立一个skydome 本章建立一个skydome(天空穹),主要学习如何使用cube mapping. cube map就是把六张纹理当作 ...
- Directx11教程(10) 画一个简易坐标轴
原文:Directx11教程(10) 画一个简易坐标轴 本篇教程中,我们将在三维场景中,画一个简易的坐标轴,分别用红.绿.蓝三种颜色表示x,y,z轴的正向坐标轴. 为此,我们要先建立一个A ...
- php表单的种类
1.text 2.color 3.date 4.datetime 5.email 6.month 7.number 8.range 9.search 10.tel 11.url 12.week 13. ...
- MaxCompute如何对SQL查询结果实现分页获取
由于MaxCompute SQL本身不提供类似数据库的select * from table limit x offset y的分页查询逻辑.但是有很多用户希望在一定场景下能够使用获取类似数据库分页的 ...
- Android中Scroller类的分析
今天看了一下项目中用到的ViewFlow控件,想弄明白其工作原理.从头开始分析,卡在"滚动"这儿了. 做android也快两年了,连最基本的滚动都不熟悉,真是惭愧...遂网上找资料 ...
- 17.使用android_studio开发libgdx
以前用eclipse开发libgdx,由于每次开机都会自检一遍安卓环境,觉得慢,就把安卓项目包给关掉了,结果再打开资源目录发生了变化,导致安卓打包不了,所以决定尝试使用as开发 首先安装as,导入gd ...
- hdu 1561【树形dp+01背包】
http://acm.hdu.edu.cn/showproblem.php?pid=1561 很容易想到如果是要攻克v城需要先攻克u城的话,可以建u到v的边.但是如果能够直接攻克u城呢?无边可建,这样 ...