ZROI1153 【线上训练3】数个数

传送门

一道非常有意思的题,涵盖了各种知识点。

首先,很显然,这是个容斥。容斥可以过掉\(30pts\)。

这里我们考虑容斥+DP。

我们令\(dp[i][j]\)代表对于前\(i\)个区间(区间排过序),上一个取的区间为\(j\)的方案数。

那么每次转移就是:

\[dp[i+1][i+1]+=-dp[i][k]*(s^{len})\space (k<i+1)
\]

其中\(len\)是这两个区间的中间部分的长度。而负号代表容斥系数(长度+1,奇偶性改变,所以变成负的)。

这个\(dp\)相当于考虑了第\(i+1\)个区间接在以不同的区间结尾的方案后面,所以可以做到不重不漏。因为在一种方案后接上一个区间对答案多出的贡献取决于这个区间和上个区间之间的距离,所以只用像这样记录上个区间即可。

下面这份代码来自An_Account,能展示出\(n^2\)的\(dp\)过程:

#include <bits/stdc++.h>
using namespace std;
const int N = 200010, mod = 998244353;
struct Query {
int l, r, b;
bool operator < (const Query &b) const {
return r < b.r || (r == b.r && l < b.l);
}
} l[N];
int dp[N];
typedef long long LL;
inline int Pow(int x, int y) {
int res = 1;
for (; y; y >>= 1, x = (LL)x * x % mod) if (y & 1) res = (LL)res * x % mod;
return res;
}
int main() {
int n, m, s; scanf("%d%d%d", &n, &m, &s);
for (int i = 1; i <= m; i++) scanf("%d%d%d", &l[i].l, &l[i].r, &l[i].b);
sort(l + 1, l + m + 1);
dp[0] = 1;
for (int i = 1; i <= m; i++)
for (int j = 0; j < i; j++) {
if (l[j].r < l[i].l || l[j].b == l[i].b) {
int t = (LL)dp[j] * Pow(s, max(0, l[i].l - l[j].r - 1)) % mod;
dp[i] = (dp[i] - t + mod) % mod;
}
}
int res = Pow(s, n);
for (int i = 1; i <= m; i++)
res = (res + (LL)dp[i] * Pow(s, n - l[i].r)) % mod;
printf("%d\n", res);
}

而正解就是在他的基础上用线段树优化转移。

首先我们发现满足转移要求有两种情况:

  1. 颜色不相同,区间不相交
  2. 颜色相同

我们考虑分开考虑两种情况,

对于第一种情况,我们可以开一个前缀和。

\[令i,j为两个区间的编号,i在j之后。\\
c[i]=\sum _{j.r<i.l} \frac{dp[j]}{s^{j.r+1}}
\]

这是因为上一个方程中的\(s^{len}\)可以这样转化:

\(s^{len}=s^{r-l+1}=\frac{s^{r+1}}{s^l}\)

因为对于一次转移,\(s^{r+1}\)都是一样的(都是当前区间的起始点),所以我们只要在\(dp[i]=-c[i]*s^{i.l}\)

然后把这个值插入在区间的右端点+1即可(查询的时候查询左端点)。

对于第二种情况,我们可以使用动态开点线段树。

因为在第一种情况里只少统计了颜色相等,区间重叠的情况。所以我们用线段树统计这种情况。

两个区间相交当且仅当第一个区间(前面的区间)的终点被第二个区间包含。那我们统计一下第二个区间内有多少个其他区间的右端点即可。因为两个区间重叠,所以在这一步只有一种方案,所以直接加上上个区间的\(dp\)值即可。(别忘了要取相反数)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define ll long long
using namespace std;
const int mod=998244353;
const int maxn=2e5+1000;
int n,m,s,ls[maxn*80],rs[maxn*80],idx,rt[maxn];
struct gg {
int l,r,b;
}q[maxn];
ll c[maxn],sum[maxn*80],dp[maxn];
void update_t(int loc,int val) {
for(int i=loc;i<=n;i+=i&-i)c[i]+=val,c[i]%=mod;
}
void push_up(int root) {
sum[root]=0;
if(ls[root])sum[root]+=sum[ls[root]];
if(rs[root])sum[root]+=sum[rs[root]];
sum[root]%=mod;
}
void update_s(int l,int r,int root,int val,int tar) {
if(l==r){sum[root]=val;sum[root]%=mod;return;}
int mid=(l+r)>>1;
if(tar<=mid) {
if(!ls[root])ls[root]=++idx;
update_s(l,mid,ls[root],val,tar);
}
if(tar>=mid+1) {
if(!rs[root])rs[root]=++idx;
update_s(mid+1,r,rs[root],val,tar);
}
push_up(root);
}
ll query_t(int loc) {
ll tot=0;for(int i=loc;i;i-=i&-i)tot+=c[i],tot%=mod;
return tot;
}
ll query_s(int l,int r,int root,int tl,int tr) {
if(tl<=l&&r<=tr)return sum[root];
int mid=(l+r)>>1;ll tot=0;
if(l<=mid&&ls[root])tot+=query_s(l,mid,ls[root],tl,tr);
if(r>=mid+1&&rs[root])tot+=query_s(mid+1,r,rs[root],tl,tr);
return tot%mod;
}
int ksm(int num,int t){
int res=1;
for(;t;t>>=1,num=(ll)num*num%mod) {
if(t&1)res=(ll)res*num%mod;
}
return res;
}
vector<gg>col[maxn];
bool cop1(gg x,gg y){if(x.l==y.l)return x.r<y.r;return x.l>y.l;}
bool cop2(gg x,gg y){return x.l<y.l;}
int main() {
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].b);
col[q[i].b].push_back(q[i]);
}
m=0;
for(int i=1;i<=s;i++) {
sort(col[i].begin(),col[i].end(),cop1);
int now=maxn;
for(int j=0;j<col[i].size();j++) {
if(col[i][j].r<now){q[++m]=col[i][j];now=col[i][j].r;}
}
}
sort(q+1,q+1+m,cop2);
dp[0]=1*ksm(s,mod-2);
update_t(1,dp[0]);//初始化
for(int i=1;i<=m;i++) {
ll t=query_t(q[i].l)*ksm(s,q[i].l);t%=mod;
if(rt[q[i].b])t+=query_s(1,n,rt[q[i].b],q[i].l,q[i].r);
dp[i]=(-t)%mod;
update_t(q[i].r+1,(dp[i]*ksm(ksm(s,q[i].r+1),mod-2)%mod));
if(!rt[q[i].b])rt[q[i].b]=++idx;
update_s(1,n,rt[q[i].b],dp[i],q[i].r);
}
ll ans=0;
for(int i=1;i<=m;i++) {
ans+=dp[i]*ksm(s,n-q[i].r);ans%=mod;
}
ans+=ksm(s,n);
ans=(ans%mod+mod)%mod;
printf("%lld",ans);
return 0;
}

ZROI1153 【线上训练3】数个数的更多相关文章

  1. 17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行。请采用循环控制语句来实现。 (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和。) 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1

    17.从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行.请采用循环控制语句来实现. (三角形腰上的数为1,其他位置的数为其上一行相邻两个数之和.) 1 1 1 1 ...

  2. 排查Java线上服务故障的方法和实例分析

    前言 作为在线系统负责人或者是一个技术专家,你可能刚刚接手一个项目就需要处理紧急故障,或者被要求帮忙处理一些紧急的故障,这个时候的情景是: (1)你可能对这个业务仅仅是听说过,而不怎么真正了解: (2 ...

  3. CSDN挑战编程——《金色十月线上编程比赛第二题:解密》

    金色十月线上编程比赛第二题:解密 题目详情: 小强是一名学生, 同一时候他也是一个黑客. 考试结束后不久.他吃惊的发现自己的高等数学科目竟然挂了,于是他果断入侵了学校教务部站点. 在入侵的过程中.他发 ...

  4. 深度学习笔记 (二) 在TensorFlow上训练一个多层卷积神经网络

    上一篇笔记主要介绍了卷积神经网络相关的基础知识.在本篇笔记中,将参考TensorFlow官方文档使用mnist数据集,在TensorFlow上训练一个多层卷积神经网络. 下载并导入mnist数据集 首 ...

  5. cdoj1339郭大侠与线上游戏

    地址:http://acm.uestc.edu.cn/#/problem/show/1339 题目: 郭大侠与线上游戏 Time Limit: 6000/2000MS (Java/Others)    ...

  6. MySQL慢日志线上问题分析及功能优化

    本文来源于数据库内核专栏. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据 ...

  7. “玲珑杯”线上赛 Round #17 河南专场

    闲来无事呆在寝室打打题,没有想到还有中奖这种操作,超开心的 玲珑杯”线上赛 Round #17 河南专场 Start Time:2017-06-24 12:00:00 End Time:2017-06 ...

  8. Arthas - Java 线上问题定位处理的终极利器

    前言 在使用 Arthas 之前,当遇到 Java 线上问题时,如 CPU 飙升.负载突高.内存溢出等问题,你需要查命令,查网络,然后 jps.jstack.jmap.jhat.jstat.hprof ...

  9. 线上Storm的worker,executor,task参数调优篇

    问题引入: 线上最近的数据量越来越大,出现了数据处理延迟的现象,观察storm ui的各项数据,发现有大量的spout失败的情况,如下: ------------------------------- ...

随机推荐

  1. Python中的passed by assignment与.NET中的passing by reference、passing by value

    Python文档中有一段话: Remember that arguments are passed by assignment in Python. Since assignment just cre ...

  2. 【MySQL】完整性约束条件与设计范式

    完整性约束条件 概念: 对表中的数据进行限定,保证数据的正确性.有效性和完整性. 分类: 主键约束:primary key 非空约束:not null 唯一约束:unique 外键约束:foreign ...

  3. Javaweb常用解决问题连接

    1.javaweb的idea如何创建及配置web项目 https://www.jianshu.com/p/8d49d36a3c7e 2.servlet的建立以及部署 https://blog.csdn ...

  4. Hystrix核心熔断器

    在深入研究熔断器之前,我们需要先看一下Hystrix的几个重要的默认配置,这几个配置在HystrixCommandProperties 中 //时间窗(ms) static final Integer ...

  5. Linux CentOS 下安装.net core sdk

    注册Microsoft密钥 sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm ...

  6. redis笔记1

    存储结构 字符类型 散列类型 列表类型 集合类型 有序集合 可以为每个key设置超时时间: 可以通过列表类型来实现分布式队列的操作 支持发布订阅的消息模式 提供了很多命令与redis进行交互 数据缓存 ...

  7. 【入门篇】前端框架Vue.js知识介绍

    一.Vue.js介绍 1.什么是MVVM? MVVM(Model-View-ViewModel)是一种软件架构设计模式,它源于MVC(Model-View-Controller)模式,它是一种思想,一 ...

  8. web自动化测试

    自动化测试主要分为下面三种: 1.单元测试(Unit Test) 对单独的代码块,比如函数进行测试.单元测试是自动化测试的主要形式,也是最基本的形式. 2.集成测试(Integration Test) ...

  9. wpf 工程生成dll

    在WPF项目里,当工程里包含窗体时候, 不可以使用类库的方式生产dll,虽然系统支持引用exe 文件,但总是觉得不如dll习惯,后来发现,新建个项目,类型选择“WPF自定义类件库”,名称和工程名称相同 ...

  10. vue学习指南:第七篇(详细) - Vue的 组件通信

    Vue 的 父传子 子传父 一.父组件向子组件传值: 父传子 把需要的数据 传递给 子组件,以数据绑定(v-bind)的形式,传递到子组件内部,供子组件使用  缩写是(:) 1.创建子组件,在src/ ...