ZROI1153 【线上训练3】数个数
ZROI1153 【线上训练3】数个数
一道非常有意思的题,涵盖了各种知识点。
首先,很显然,这是个容斥。容斥可以过掉\(30pts\)。
这里我们考虑容斥+DP。
我们令\(dp[i][j]\)代表对于前\(i\)个区间(区间排过序),上一个取的区间为\(j\)的方案数。
那么每次转移就是:
\]
其中\(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);
}
而正解就是在他的基础上用线段树优化转移。
首先我们发现满足转移要求有两种情况:
- 颜色不相同,区间不相交
- 颜色相同
我们考虑分开考虑两种情况,
对于第一种情况,我们可以开一个前缀和。
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】数个数的更多相关文章
- 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 ...
- 排查Java线上服务故障的方法和实例分析
前言 作为在线系统负责人或者是一个技术专家,你可能刚刚接手一个项目就需要处理紧急故障,或者被要求帮忙处理一些紧急的故障,这个时候的情景是: (1)你可能对这个业务仅仅是听说过,而不怎么真正了解: (2 ...
- CSDN挑战编程——《金色十月线上编程比赛第二题:解密》
金色十月线上编程比赛第二题:解密 题目详情: 小强是一名学生, 同一时候他也是一个黑客. 考试结束后不久.他吃惊的发现自己的高等数学科目竟然挂了,于是他果断入侵了学校教务部站点. 在入侵的过程中.他发 ...
- 深度学习笔记 (二) 在TensorFlow上训练一个多层卷积神经网络
上一篇笔记主要介绍了卷积神经网络相关的基础知识.在本篇笔记中,将参考TensorFlow官方文档使用mnist数据集,在TensorFlow上训练一个多层卷积神经网络. 下载并导入mnist数据集 首 ...
- cdoj1339郭大侠与线上游戏
地址:http://acm.uestc.edu.cn/#/problem/show/1339 题目: 郭大侠与线上游戏 Time Limit: 6000/2000MS (Java/Others) ...
- MySQL慢日志线上问题分析及功能优化
本文来源于数据库内核专栏. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据 ...
- “玲珑杯”线上赛 Round #17 河南专场
闲来无事呆在寝室打打题,没有想到还有中奖这种操作,超开心的 玲珑杯”线上赛 Round #17 河南专场 Start Time:2017-06-24 12:00:00 End Time:2017-06 ...
- Arthas - Java 线上问题定位处理的终极利器
前言 在使用 Arthas 之前,当遇到 Java 线上问题时,如 CPU 飙升.负载突高.内存溢出等问题,你需要查命令,查网络,然后 jps.jstack.jmap.jhat.jstat.hprof ...
- 线上Storm的worker,executor,task参数调优篇
问题引入: 线上最近的数据量越来越大,出现了数据处理延迟的现象,观察storm ui的各项数据,发现有大量的spout失败的情况,如下: ------------------------------- ...
随机推荐
- KVM virsh console
(1) 查看正在运行的虚拟机 root@kvm:~# virsh list Id Name State ------------------------------------------------ ...
- DVWA-文件包含学习笔记
DVWA-文件包含学习笔记 一.文件包含与漏洞 文件包含: 开发人员将相同的函数写入单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写,这种文件调用的过程称文件包含. 文件包含漏洞: 开发人 ...
- ASP.NET MVC过滤器学习笔记
1.过滤器的两个特征 1.他是一种特性,可以引用到控制器类和Action方法上.比如下图 这里控制器类和action方法都引用了过滤器,这个过滤器是用来做授权的 2.特征继承自FilterAttrib ...
- c# 值类型和引用类型 笔记
参考以下博文,我这里只是笔记一下,原文会更加详细 c#基础系列1---深入理解值类型和引用类型 堆栈和托管堆c# 值类型和引用类型 红色表示——“这啥?”(真实1个问题引出3个问题) CLR支持的两种 ...
- python 跟踪IP模块
#coding=utf-8 import re import subprocess def tracertIP(ip): p = subprocess.Popen(['tracert',ip],std ...
- Flask补充--threading.local对象
目录 Local 局部变量 全局变量 使用threading.local() 自定义threading.local 函数版 面向对象版 通过setattr和getattr实现 每个对象有自己的存储空间 ...
- Lucene搜索/索引过程笔记
lucene索引文档过程: > 初始化IndexWriter > 构建Document > 调用IndexWriter.addDocument执行写入 > 初始化Documen ...
- 什么是LNMP架构
LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写.L指Linux,N指Nginx,M一般指MySQL,也可以指MariaDB,P一般指PHP,也可以指Perl或Python ...
- PHP-FPM Fastcgi 未授权访问漏洞
漏洞原理 Fastcgi Fastcgi是一个通信协议,和HTTP协议一样,都是进行数据交换的一个通道.HTTP协议是浏览器和服务器中间件进行数据交换的协议,浏览器将HTTP头和HTTP体用某个规则组 ...
- Spring Boot实战之定制自己的starter
本文首发于个人网站,原文地址:http://www.javaadu.online/?p=535,如需转载,请注明出处 在学习Spring Boot的过程中,接触最多的就是starter.可以认为sta ...