首页 > 其他分享 >[题解]P7077 [CSP-S2020] 函数调用

[题解]P7077 [CSP-S2020] 函数调用

时间:2024-10-04 17:03:39浏览次数:9  
标签:cnt 函数 int 题解 函数调用 mul P7077 节点 cur

P7077 [CSP-S2020] 函数调用

题意简述

给定一个长度为\(n\)的序列\(a_1,a_2,\dots,a_n\),给定\(m\)个函数,每个函数可能是下面\(3\)种类型,用\(T_x\)表示函数\(x\)的类型:

  • \(T_x =1\),对下标\(p\)增加\(v\)。
  • \(T_x =2\),对所有元素乘\(v\)。
  • \(T_x =3\),由若干类型\(1\)和类型\(2\)组成的复合函数,按顺序执行。

给定初始序列和每个函数的定义,最后给定一个调用序列,你需要按顺序调用完该序列所有函数后输出序列。

思路分析

我们把函数看作节点,调用关系看作有向边(调用连向被调用),因为没有递归调用,所以这是一个DAG(有向无环图)。

由于乘法是区间的,所以最终每个\(a_i\)都可以表示为\(a_i\times k+b_i\)。其中\(k\)就是函数序列中每个函数的\(mul\)值之积,其中\(mul_i\)的定义如下:

  • \(i\)是类型\(1\)函数:\(mul_i=1\)。
  • \(i\)是类型\(2\)函数:\(mul_i=v\)。
  • \(i\)是类型\(3\)函数:\(mul_i=\prod\limits_{i\rightarrow j} mul_j\)。

这样\(k\)就计算出来了。

我们接下来要计算\(b_i\),那么需要知道每个\(1\)类函数被执行了多少次,我们记第\(1\)类函数\(x\)被执行的次数为\(cnt_x\),那么\(b_i=\sum\limits_{T_{_j}=1,p_{_j}=i}v_j\times cnt_j\)。

先考虑没有类型\(2\)函数的情况,我们只需要对于调用的每个函数\(i\),将\(cnt_i \leftarrow cnt_i +1\),然后再DAG上递推,把父节点的\(cnt\)推给子节点即可。最后对于每个叶子结点(类型\(1,2\)的函数)中类型为\(1\)的函数\(i\),将\(cnt_i\times v_i\)加给\(p_i\)即可。

如果有类型\(2\)函数,我们推给子节点的\(cnt\)可能会乘上一个系数,假设我们当前遍历到节点\(u\),有\(s\)个子节点,对于第\(i\)个子节点\(son_i\),\(u\)对\(son_i\)的贡献是\(cnt_u\times cur\),其中\(cur=\prod\limits_{j=i+1}^{s} mul_i\)。这是因为后面函数的“乘”操作会影响到前面的函数。所以我们可以倒序遍历子节点,累乘贡献即可。

相应地,主函数中为\(sum\)赋初值也需要累乘贡献。


也可以这样思考:序列初始为\(0\),第\(i\)位增加\(a_i\)作为\(n\)个函数额外放在其他函数前执行。这样输出就不用管\(a_i\times k\)了,只要输出\(b_i\)即可。

Code

#include<bits/stdc++.h>
#define N 100010
#define mod 998244353
#define int long long
using namespace std;
int n,m,q,a[N],deg[N],fun[N];
int p[N],v[N];//存储叶子节点(操作1,2)的信息 
int ord[N],tn;//ord[i]表示拓扑序为i的节点,tn为计数器 
int mul[N];//mul[i]表示函数i要乘多少
int cnt[N];//cnt[i]表示函数i要执行多少次 
vector<int> G[N];
queue<int> que;
void topo(){//预处理出拓扑序,方便转移
	for(int i=1;i<=m;i++)
		if(!deg[i]) que.push(i);
	while(!que.empty()){
		int u=que.front();
		que.pop(),ord[++tn]=u;
		for(int i:G[u]){
			deg[i]--;
			if(!deg[i]) que.push(i);
		}
	}
}
void getmul(){//自下而上计算节点的mul
	for(int i=m;i>=1;i--){
		int u=ord[i];
		for(int j:G[u]) mul[u]=mul[u]*mul[j]%mod;
	}
}
void getsum(){//自上而下计算节点的sum 
	for(int i=1;i<=m;i++){
		int u=ord[i],cur=cnt[u];
		for(int j:G[u])
			cnt[j]=(cnt[j]+cur%mod)%mod,
			cur=cur*mul[j]%mod;
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cin>>m;
	for(int i=1;i<=m;i++){
		int op;
		cin>>op;
		if(op==1){
			cin>>p[i]>>v[i];
			mul[i]=1;
		}else if(op==2){
			cin>>v[i];
			mul[i]=v[i];
		}else{
			int c,v;
			cin>>c;
			mul[i]=1;
			while(c--){
				cin>>v;
				G[i].emplace_back(v);
				deg[v]++;
			}
		}
	}
	for(int i=1;i<=m;i++) reverse(G[i].begin(),G[i].end());//倒序遍历
	topo();
	getmul();
	cin>>q;
	int cur=1;
	for(int i=1;i<=q;i++) cin>>fun[i];
	for(int i=q;i>=1;i--){
		int u=fun[i];
		cnt[u]=(cnt[u]+cur)%mod;
		cur=cur*mul[u]%mod;
	}
	getsum();
	for(int i=1;i<=n;i++) a[i]=a[i]*cur%mod;
	for(int i=1;i<=m;i++){
		if(p[i]) a[p[i]]=(a[p[i]]+v[i]*cnt[i]%mod)%mod;
	}
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	return 0;
}

标签:cnt,函数,int,题解,函数调用,mul,P7077,节点,cur
From: https://www.cnblogs.com/Sinktank/p/18446528

相关文章

  • 【题解】B - 三元上升子序列
    目录题目内容DescriptionInputOutput数据规模与约定思路代码题目内容DescriptionErwin最近对一种叫thair的东西巨感兴趣。。。在含有\(n\)个整数的序列\(a_1,a_2,\ldots,a_n\)中,三个数被称作thair当且仅当\(i\ltj\ltk\)且\(a_i\lta_j\lta_k\)。求一个序列中thair......
  • BUUCTF_MISC题解析(3,4)
    3.你竟然赶我走搜索010editor官网,点第一个页面,下载010editor(十六进制编译器)(黄色图标),直接010editor打开(或者使用stegSolve)一般情况用ctrl+f进入字符串搜索查看是否有插入的flag信息,就可以在文件尾看到flag是flag{stego_is_s0_bor1ing} 4.二维码扫码识别二维码,发现隐......
  • 【题解】Solution Set - NOIP2024集训Day42 博弈论
    【题解】SolutionSet-NOIP2024集训Day42博弈论https://www.becoder.com.cn/contest/5574https://www.cnblogs.com/CloudWings/p/17813917.html「中山市选2009」谁能赢呢?一道经典的「二分图博弈」在棋盘问题上的应用。https://www.luogu.com.cn/article/h8a79k3i......
  • [题解](更新中)MX-X6 A~B
    Portal:https://www.luogu.com.cn/contest/200833A-もしも容易发现可以构造\(1,x\)或\(x,1\)让序列如\(\dots,1,x,1,x,1,x,\dots\)这样循环。只需要关注\(n\)的奇偶性即可。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intt,n,an;si......
  • [题解]SFMOI Round I A~C
    Portal:https://www.luogu.com.cn/contest/179008\(\bf{100+50+50+25+5=\color{indianred}225\color{black}\,\rk.\184}\)A-StrangeCakeGame显然对于小W,向下移动蛋糕刀是最有利的;对于小M,向右移动是最有利的。所以双方以最佳状态移动,最终\(x\ley\)的巧克力是小W的。直接......
  • 【题解】「CF765F」Souvenirs
    https://www.luogu.com.cn/problem/CF765F首先有一个比较navie的\(O(n\sqrtm\logn)\)的做法(add和del的时候,用两个multiset维护一下。有一个bitset的做法来优化用multiset查询前驱后继的做法:https://www.luogu.com.cn/article/zcmco6hd首先考虑离线下来,将询问挂......
  • CF154C题解
    传送门:https://codeforces.com/problemset/problem/154/C求出无向图中,满足所有出边都相连或出边直接连接点对的点对数。很显然可以暴力枚举点对一对对去check,时间复杂度\(O(n^2+m)\)。#include<bits/stdc++.h>usingnamespacestd;inlineintread(){charc;boo......
  • 构树 题解
    构树题解好题,除了毒瘤卡空间。“恰好”这个形式很二项式反演。设\(f(n)\)表示树上钦定\(n\)条边和原树相同的方案数,\(g(n)\)表示树上恰好有\(n\)条边和原树相同的方案数,那么原先的形式是:\[f(n)=\sum_{i\gen}{i\choosen}g(i)\]二项式反演得到:\[g(n)=\sum_{i\gen}(......
  • QOJ 8726 [APIO2024] 魔术表演 题解
    DescriptionAlice和Bob是著名的魔术师。Catherine是一位富豪,她非常喜欢观看Alice和Bob的魔术。某一天,Catherine决定向Alice和Bob发出挑战:只要他们能成功表演如下的魔术,Catherine就将向他们提供巨额奖金!这个魔术的表演过程如下:步骤\(1\):Bob进⼊⼀个密室中,在魔术......
  • 题解:洛谷P2339 [USACO04OPEN] Turning in Homework G
    题目链接:洛谷P2339[USACO04OPEN]TurninginHomeworkG首先我们考虑如何处理到达给定时间后才能交作业这一限制。其实在生活中,我们一般只会考虑什么时候交作业截止(除了某些卷王),这样我们只用考虑如何在最大结束时间之前交作业,而不是在所有作业都没开始交之前考虑如何转悠(前者明......