当前位置: 首页 > news >正文

2020 CCF CSP-S2.函数调用

题目

2773. 函数调用
在这里插入图片描述

算法标签: 拓扑排序, 组合计数

思路

算每个函数最终对答案的贡献是多少, 计算当期加法但是要计算后面乘法的贡献, 用乘法原理加法原理计算每个函数等效的执行次数, 时间复杂度是线性的 O ( n ) O(n) O(n)

为什么 m u l mul mul需要按照拓扑序的逆序计算?
假设函数 A A A调用了函数 B B B和函数 C C C, 那么 A A A的最终的 m u l mul mul是取决于 B B B C C C m u l mul mul的, 因此需要按照拓扑序的逆序倒着推, 类似于动态规划的过程, 确保当前状态已经被计算

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef long long LL;
const int N = 1e5 + 10, M = 1e6 + 10, MOD = 998244353;

int n, m, q_num;
vector<int> head[N];
int w[N], g[N];
int q[N], deg[N];
struct Func {
	int t, pos, val;
	int mul;
	int sum;
} f[N];

void add(int u, int v) {
	head[u].push_back(v);
}

void top_sort() {
	int h = 0, t = -1;
	for (int i = 1; i <= m; ++i) {
		if (deg[i] == 0) q[++t] = i;
	}

	while (h <= t) {
		int u = q[h++];
		for (int v: head[u]) {
			if (--deg[v] == 0) q[++t] = v;
		}
	}
}

void calc_mul() {
	for (int i = m - 1; i >= 0; --i) {
		int u = q[i];
		for (int v : head[u]) {
			f[u].mul = (LL) f[u].mul * f[v].mul % MOD;
		}
	}
}

void calc_sum() {
	for (int i = 0; i < m; ++i) {
		int u = q[i];
		int sum = f[u].sum;
		for (int v : head[u]) {
			f[v].sum = (f[v].sum + sum) % MOD;
			sum = (LL) sum * f[v].mul % MOD;
		}
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	cin >> n;
	for (int i = 1; i <= n; ++i) cin >> w[i];
	cin >> m;

	for (int i = 1; i <= m; ++i) {
		cin >> f[i].t;
		if (f[i].t == 1) cin >> f[i].pos >> f[i].val;
		else if (f[i].t == 2) cin >> f[i].val;
		else {
			int cnt;
			cin >> cnt;
			vector<int> tmp;
			while (cnt--) {
				int x;
				cin >> x;
				tmp.push_back(x);
			}
			// 为了保证结果是正确的, 需要从最后一个子函数向前计算
			reverse(tmp.begin(), tmp.end());
			for (int x: tmp) {
				add(i, x);
				deg[x]++;
			}
		}
	}

	// 初始化乘法因子
	for (int i = 1; i <= m; ++i) {
		if (f[i].t == 2) {
			f[i].mul = f[i].val;
		}
		else {
			f[i].mul = 1;
		}
	}

	top_sort();
	calc_mul();

	cin >> q_num;
	for (int i = 1; i <= q_num; ++i) cin >> g[i];

	// 计算全局的乘法标记和加法标记
	int sum = 1;
	for (int i = q_num; i >= 1; --i) {
		int k = g[i];
		f[k].sum = (f[k].sum + sum) % MOD;
		sum = (LL) sum * f[k].mul % MOD;
	}

	calc_sum();

	// 应用全局乘法
	for (int i = 1; i <= n; ++i) {
		w[i] = (LL) w[i] * sum % MOD;
	}

	// 处理类型1的加法操作
	for (int i = 1; i <= m; ++i) {
		if (f[i].t == 1) {
			w[f[i].pos] = (w[f[i].pos] + (LL) f[i].val * f[i].sum) % MOD;
		}
	}

	for (int i = 1; i <= n; ++i) cout << w[i] << " ";
	cout << "\n";

	return 0;
}
http://www.dtcms.com/a/125012.html

相关文章:

  • IP属地和所在地不一致什么意思?怎么换成另外一个地方的
  • 【MATLAB第114期】基于MATLAB的SHAP可解释神经网络分类模型(敏感性分析方法)
  • [ctfshow web入门] web40
  • 【Kubernetes】Kubernetes 如何进行日志管理?Fluentd / Loki / ELK 适用于什么场景?
  • vue辅助工具(vue系列二)
  • MySQL8.0.31安装教程,附pdf资料和压缩包文件
  • 【Grok 大模型深度解析】第一期:技术溯源与核心突破
  • openEuler 24.03安装docker,docker compose
  • arthas之profiler火焰图基本使用和实践
  • Elasticsearch 向量数据库,原生支持 Google Cloud Vertex AI 平台
  • 光谱相机的关键技术参数
  • Vue3+Vite+TypeScript+Element Plus开发-12.动态路由-动态增加路由
  • 精准测试建设过程中遇到的一些问题
  • 思科交换机配置
  • 电力人工智能多模态大模型创新技术及应用|西安交通大学
  • TCPIP详解 卷1协议 三 链路层
  • mysql 创建时间限定格式查询
  • SpringBoot多线程,保证各个子线程和主线程事物一致性
  • 使用 Rsync + Lsyncd 实现 CentOS 7 实时文件同步
  • 双相机结合halcon的条码检测
  • 大模型论文:CRAMMING TRAINING A LANGUAGE MODEL ON ASINGLE GPU IN ONE DAY(效率提升)-final
  • LeetCode 解题思路 36(Hot 100)
  • 自适应LL解析的终极进化:ALL(*)算法如何改写语法解析规则
  • 动态词槽管理系统深度设计
  • YOLO11改进-模块-引入门控瓶颈卷积GBC 关注目标抑制背景干扰
  • OpenEuler运维实战-(OS|硬件信息-软件信息-日志)信息收集!
  • Linux服务器网卡深度解析:从ifconfig输出到生产环境性能调优实战
  • 力扣刷题Day 15:二叉树中的最大路径和(124)
  • [ctfshow web入门] web32
  • 【场景应用1】微调语言模型:从数据加载到模型训练、模型评估