函数调用:个人非常喜欢的一道拓扑题。

转化

这题一共有三种操作,不太好搞。而第一个函数看起来就比较可做,第三个函数显然就是让你拓扑转移,于是我们考虑第二个操作怎么处理。

当我们进行一个操作一后,假设当前节点的增量为 \(ad\)。此时如果再进行一次操作二,全局乘上 \(mul\),那么该节点最终的增量为 \(ad\times mul\)。根据乘法的定义,我们可以把这个增量转化为对该节点进行 \(mul\) 次操作一。

这就启发了我们考虑每个操作一会被执行多少次,显然是这个操作后面的操作的后缀积。

于是这题最关键的一步转化就做完了。

拓扑

因为操作三是要依次执行操作,也就是说它的子操作执行时,乘上的操作次数可能不相同。

因此,我们可以先预处理出每个操作完成之后会给全局乘上什么数,以便后面的计算。这可以通过倒着拓扑一遍处理。

接下来就要转移函数执行次数了,我们定义 \(dp_i\) 表示该操作要被执行的次数。

显然,我们可以倒着枚举执行的操作,维护该操作内部的后缀积 \(nmul\),进行如下转移:

\[dp_v \gets dp_v+dp_u \times nmul
\]

这就保证了前面的操作一定会算上后面函数的乘积了。

那么该如何初始化呢?同样是倒序枚举它给定的操作,维护一个后缀积,处理到某个操作的初始值时,其初始值就是当前的后缀积。

最后统计答案是容易的,因为只剩下操作一了,只要我们依次累计上答案即可。注意原来的值要乘上所有操作的全局积。

时间复杂度 \(O(m)\)。

实现

这题码量较大,再次梳理一遍代码过程:

  1. 倒着拓扑一遍,计算出每个函数操作之后给全局乘了多少。
  2. 倒着操作所有函数调用,实时维护一个后缀乘积,然后给各函数打标记。
  3. 顺着拓扑一遍,对于第三种函数,我们倒着枚举它的出边,然后进行转移,转移之后乘上对应节点的全局乘贡献。

代码

以上三个步骤在代码中被拆分成了三个函数来实现。

注意所有时候都要取模。

#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 函数调用 题解 [ 蓝 ] [ 拓扑排序 ] [ 动态规划 ] [ 数学 ]的更多相关文章

  1. 【BZOJ1471】不相交路径 题解(拓扑排序+动态规划+容斥原理)

    题目描述 在有向无环图上给你两个起点和终点分别为$a,b,c,d$.问有几种路径方案使得能从$a$走到$b$的同时能从$c$走到$d$,且两个路径没有交点. $1\leq n\leq 200,1\le ...

  2. 洛谷 P3244 / loj 2115 [HNOI2015] 落忆枫音 题解【拓扑排序】【组合】【逆元】

    组合计数的一道好题.什么非主流题目 题目背景 (背景冗长请到题目页面查看) 题目描述 不妨假设枫叶上有 \(n​\) 个穴位,穴位的编号为 \(1\sim n​\).有若干条有向的脉络连接着这些穴位. ...

  3. bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划

    一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...

  4. Luogu3953 NOIP2017逛公园(最短路+拓扑排序+动态规划)

    跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ...

  5. [luogu]P4316 绿豆蛙的归宿(拓扑排序,期望)

    P4316 绿豆蛙的归宿 题目背景 随着新版百度空间的上线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 题目描述 给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出发能够 ...

  6. ACM/ICPC 之 拓扑排序范例(POJ1094-POJ2585)

    两道拓扑排序问题的范例,用拓扑排序解决的实质是一个单向关系问题 POJ1094(ZOJ1060)-Sortng It All Out 题意简单,但需要考虑的地方很多,因此很容易将code写繁琐了,会给 ...

  7. 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 ...

  8. Ordering Tasks(拓扑排序+dfs)

    Ordering Tasks John has n tasks to do. Unfortunately, the tasks are not independent and the executio ...

  9. 【紫书】Ordering Tasks UVA - 10305 拓扑排序:dfs到底再输出。

    题意:给你一些任务1~n,给你m个数对(u,v)代表做完u才能做v 让你给出一个做完这些任务的合理顺序. 题解:拓扑排序版题 dfs到底再压入栈. #define _CRT_SECURE_NO_WAR ...

  10. 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 ...

随机推荐

  1. 内网穿透之frp

    官网文档:https://gofrp.org 1 Frp介绍frp 是一个开源.简洁易用.高性能的内网穿透和反向代理软件,支持 tcp, udp, http, https等协议.frp 项目官网是 h ...

  2. python之数据库管理工具sandman2

    文档:Welcome to sandman2's documentation! - sandman2 0.0.1 documentation [安装] pip install sandman2 安装成 ...

  3. 打包jar 程序,同时将依赖报一起打包

    1.概述 有些时候,我们打包一个java 程序,我需要将所有的依赖也一起打包,这样执行起来方便. 2.我们可以使用maven 插件实现 <build> <plugins> &l ...

  4. Git 浅克隆后拉取其他分支

    对于已浅克隆的项目 $ git clone --depth=1 <git-repo-url> repo $ cd repo 现在浅克隆了一个Git仓库repo.但仓库里查询远程分支只有一个 ...

  5. 前端17号学习(html完结)

    一.路径 1.目录文件夹和跟目录 实际工作中需要创建一个文件夹来管理他们. 目录文件夹,就是普通文件夹,里面存放页面相关素材,如html文件.图片等. 根目录,打开目录文件夹的第一层就是根目录. 2. ...

  6. 2024-12-18:正方形中的最多点数。用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签。 如果一个正

    2024-12-18:正方形中的最多点数.用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签. 如果一个正 ...

  7. Flutter 错误The argument type 'Color' can't be assigned to the parameter type 'MaterialStateProperty<Color?>?'.dart(argument_type_not_assignable)

    MaterialStateProperty<Color?>?和Color 当为TextButton等button添加颜色时,使用ButtonStyle为其添加颜色 TextButton( ...

  8. 【Word】文献引用批量上标

    \[([0-9]{1,2})\]

  9. MockQueryable:LINQ查询模拟测试工具

    我们在项目开发过程中,单元测试是确保代码质量的重要环节.涉及数据库LINQ查询逻辑,就需要数据库配合,但这样可能出现性能和数据库并发等问题.下面给推荐一个开源库,为开发者提供了一种简便的方式来模拟LI ...

  10. 黑苹果(Hackintosh) - 安装1:用 VMware pro 16 安装 Big Sur 11.6

    1. 背景情况 1.1 想法 想要体验体验macOS系统,不想花钱买 Macbook,就想着 装一个黑苹果体验下. 1.2 本机基本情况 笔记本:zx6 cp5s1 CPU:i5 8400 主板:H3 ...