Luogu P7077 CSP-S2020 函数调用 题解 [ 蓝 ] [ 拓扑排序 ] [ 动态规划 ] [ 数学 ]
函数调用:个人非常喜欢的一道拓扑题。
转化
这题一共有三种操作,不太好搞。而第一个函数看起来就比较可做,第三个函数显然就是让你拓扑转移,于是我们考虑第二个操作怎么处理。
当我们进行一个操作一后,假设当前节点的增量为 \(ad\)。此时如果再进行一次操作二,全局乘上 \(mul\),那么该节点最终的增量为 \(ad\times mul\)。根据乘法的定义,我们可以把这个增量转化为对该节点进行 \(mul\) 次操作一。
这就启发了我们考虑每个操作一会被执行多少次,显然是这个操作后面的操作的后缀积。
于是这题最关键的一步转化就做完了。
拓扑
因为操作三是要依次执行操作,也就是说它的子操作执行时,乘上的操作次数可能不相同。
因此,我们可以先预处理出每个操作完成之后会给全局乘上什么数,以便后面的计算。这可以通过倒着拓扑一遍处理。
接下来就要转移函数执行次数了,我们定义 \(dp_i\) 表示该操作要被执行的次数。
显然,我们可以倒着枚举执行的操作,维护该操作内部的后缀积 \(nmul\),进行如下转移:
\]
这就保证了前面的操作一定会算上后面函数的乘积了。
那么该如何初始化呢?同样是倒序枚举它给定的操作,维护一个后缀积,处理到某个操作的初始值时,其初始值就是当前的后缀积。
最后统计答案是容易的,因为只剩下操作一了,只要我们依次累计上答案即可。注意原来的值要乘上所有操作的全局积。
时间复杂度 \(O(m)\)。
实现
这题码量较大,再次梳理一遍代码过程:
- 倒着拓扑一遍,计算出每个函数操作之后给全局乘了多少。
- 倒着操作所有函数调用,实时维护一个后缀乘积,然后给各函数打标记。
- 顺着拓扑一遍,对于第三种函数,我们倒着枚举它的出边,然后进行转移,转移之后乘上对应节点的全局乘贡献。
代码
以上三个步骤在代码中被拆分成了三个函数来实现。
注意所有时候都要取模。
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
const ll mod=998244353;
int n,m,rd[100005],frd[100005],q,opf[100005];
ll a[100005],mul[100005],dp[100005],allmul,ad[100005];
struct node{
int tp,p;
ll v;
}f[100005];
vector<int>g[100005],fg[100005];
void topo1()
{
queue<int>q;
for(int i=1;i<=m;i++)
{
if(frd[i]==0)q.push(i);
if(f[i].tp==2)mul[i]=f[i].v;
else mul[i]=1;
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(auto v:fg[u])
{
mul[v]=(mul[v]*mul[u])%mod;
frd[v]--;
if(frd[v]==0)q.push(v);
}
}
}
void init()
{
ll nmul=1;
for(int i=q;i>=1;i--)
{
dp[opf[i]]=(dp[opf[i]]+nmul)%mod;
nmul=(nmul*mul[opf[i]])%mod;
}
allmul=nmul;
}
void topo2()
{
queue<int>q;
for(int i=1;i<=m;i++)if(rd[i]==0)q.push(i);
ll nmul=1;
while(!q.empty())
{
int u=q.front();
q.pop();
nmul=1;
for(int i=g[u].size()-1;i>=0;i--)
{
int v=g[u][i];
dp[v]=(dp[v]+dp[u]*nmul%mod)%mod;
nmul=(nmul*mul[v])%mod;
rd[v]--;
if(rd[v]==0)q.push(v);
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
cin>>m;
for(int i=1;i<=m;i++)
{
int tp,p,v;
cin>>tp;
if(tp==1)
{
cin>>p>>v;
f[i]={1,p,v};
}
else if(tp==2)
{
cin>>v;
f[i]={2,0,v};
}
else
{
cin>>p;
for(int j=1;j<=p;j++)
{
int to;
cin>>to;
g[i].push_back(to);
rd[to]++;
fg[to].push_back(i);
frd[i]++;
}
f[i]={3,p,0};
}
}
cin>>q;
for(int i=1;i<=q;i++)cin>>opf[i];
topo1();
init();
topo2();
for(int i=1;i<=m;i++)if(f[i].tp==1)ad[f[i].p]=(ad[f[i].p]+dp[i]*f[i].v%mod)%mod;
for(int i=1;i<=n;i++)cout<<(allmul*a[i]%mod+ad[i])%mod<<" ";
return 0;
}
Luogu P7077 CSP-S2020 函数调用 题解 [ 蓝 ] [ 拓扑排序 ] [ 动态规划 ] [ 数学 ]的更多相关文章
- 【BZOJ1471】不相交路径 题解(拓扑排序+动态规划+容斥原理)
题目描述 在有向无环图上给你两个起点和终点分别为$a,b,c,d$.问有几种路径方案使得能从$a$走到$b$的同时能从$c$走到$d$,且两个路径没有交点. $1\leq n\leq 200,1\le ...
- 洛谷 P3244 / loj 2115 [HNOI2015] 落忆枫音 题解【拓扑排序】【组合】【逆元】
组合计数的一道好题.什么非主流题目 题目背景 (背景冗长请到题目页面查看) 题目描述 不妨假设枫叶上有 \(n\) 个穴位,穴位的编号为 \(1\sim n\).有若干条有向的脉络连接着这些穴位. ...
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...
- Luogu3953 NOIP2017逛公园(最短路+拓扑排序+动态规划)
跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ...
- [luogu]P4316 绿豆蛙的归宿(拓扑排序,期望)
P4316 绿豆蛙的归宿 题目背景 随着新版百度空间的上线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 题目描述 给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出发能够 ...
- ACM/ICPC 之 拓扑排序范例(POJ1094-POJ2585)
两道拓扑排序问题的范例,用拓扑排序解决的实质是一个单向关系问题 POJ1094(ZOJ1060)-Sortng It All Out 题意简单,但需要考虑的地方很多,因此很容易将code写繁琐了,会给 ...
- Codeforces Round #292 (Div. 1) B. Drazil and Tiles 拓扑排序
B. Drazil and Tiles 题目连接: http://codeforces.com/contest/516/problem/B Description Drazil created a f ...
- Ordering Tasks(拓扑排序+dfs)
Ordering Tasks John has n tasks to do. Unfortunately, the tasks are not independent and the executio ...
- 【紫书】Ordering Tasks UVA - 10305 拓扑排序:dfs到底再输出。
题意:给你一些任务1~n,给你m个数对(u,v)代表做完u才能做v 让你给出一个做完这些任务的合理顺序. 题解:拓扑排序版题 dfs到底再压入栈. #define _CRT_SECURE_NO_WAR ...
- Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) E. Tree Folding 拓扑排序
E. Tree Folding 题目连接: http://codeforces.com/contest/765/problem/E Description Vanya wants to minimiz ...
随机推荐
- sql注入-数据库表基本操作
一.数据库 linux下登录: mysql -u root -p 查看数据库: show databases; 可以在phpmyadmin面板点击SQL进行操作 1. 增加/创建 创建xxx数据库,并 ...
- uni-app 横竖屏问题
前情 uni-app是我很喜欢的跨平台框架,它能开发小程序,H5,APP(安卓/iOS),对前端开发很友好,自带的IDE让开发体验也很棒,公司项目就是主推uni-app 坑位 最近有用户反馈闪屏页也叫 ...
- Windows的树形目录结构
一.文件.文件夹(目录).逻辑盘.路径的概念 · 文件:是操作系统用来存储和管理信息的基本单位.每个文件都有一个名称,叫文件名.文件名通常由基本文件名和扩展名两部分组成,其中基本文件名用于说明文件 ...
- 【原创】xenomai环境下开源实时数控系统LinuxCNC编译安装
linuxcnc 在xenomai下的构建简单记录,参考链接https://www.linuxcnc.org/docs/devel/html/code/building-linuxcnc.html 1 ...
- 会话丢失-NGINX配置之underscores_in_headers
1.描述问题NGINX代理某个web服务时,单机情况下也出现不停的要求认证的情况 初步分析去掉NGINX代理,直接访问服务,未出现上述情况: 进一步分析:查看经过NGINX的请求和直接访问服务请求区别 ...
- 工具大全-dirsearch探测Web目录
dirsearch介绍 dirsearch是一款开源的.基于Python开发的命令行工具,主要用于对Web服务器进行目录和文件的扫描,以发现潜在的安全漏洞. dirsearch下载地址: https: ...
- Qt/C++编写onvif工具(搜索/云台/预置位/OSD/录像存储)
一.前言 从最初编写这个工具开始的时间算起来,至少5年多,一直持续完善到今天,这个工具看起来小也不小大也不大,但是也是经历过无数个现场的洗礼,毫不夸张的说,市面上能够遇到的主流的厂商的设备,都测试过, ...
- Qt音视频开发28-ffmpeg解码本地摄像头(yuv422转yuv420)
一.前言 一开始用ffmpeg做的是视频流的解析,后面增加了本地视频文件的支持,到后面发现ffmpeg也是支持本地摄像头设备的,只要是原则上打通的比如win系统上相机程序.linux上茄子程序可以正常 ...
- 从零开始构建一个基于大模型和 RAG 的知识库问答系统
SimpleAbdQA 本项目所使用的大模型为:qwen1.8b 演示中所使用Embedding为:Word2vec 一.介绍 通过从本项目中,你可以得到: 了解基于大模型的本地知识库的运作原理 了解 ...
- CSP-J2/S2 2024 游记
前情提要:CSP-J/S 2023 写这篇文章的时候,心情比较复杂. 哎,结局还算圆满. 初赛 之前那个写的不好再写一遍() 两个都在 WFLS,也就是本校考 qaq. J 在大礼堂考,没啥好说的,太 ...