ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CSP-S2020] 函数调用 题解

2021-10-22 09:02:58  阅读:196  来源: 互联网

标签:ch int 题解 函数调用 add 操作 mul CSP dp


明天就是CSP-S了 今天打算复习下板子 把这道T3题解顺便写一下吧

题目大意是有三种函数

  1. 给数据中指定元素加上一个值
  2. 给数据所有元素都乘上一个值
  3. 调用1.2两种函数

如果没有3操作 想必大家应该都会吧(坚信)

一开始我也想到线段树 但是线段树只能拿30分

逃出sb数据结构的圈子 认真想想此题

题目说不存在调用自己的情况 也就是对于3操作来说它所调用的一定是之前的1,2函数 所以会发现整个函数调用关系事实上是一个有向无环图

对于有向无环图处理方式就很多了,不妨考虑记忆化搜索或者dp

我们发现 对于一个加法操作而言 如果它后面有若干乘法操作(假设操作了n次)

\(那么相当于它做了\prod_{i = 1}^{n} val_{i} 次的加法\)

于是我们只需要记下每个函数调用后所有数会被乘多少,以及对加法操作的贡献

\(分 别记其为 mul_{i} 和 dp_{i}\)

\(mul_{i} 可以dfs直接计算出来(因为是一个DAG)\)

\(然后我们思考如何计算 dp_{i}\)

首先我们必须从后往前计算 因为事实上能影响一个加法的只有其后所有的乘法操作

  • \(对于操作一而言 dp_{i} = dp_{i} + mul(mul为其后所有的乘法操作)\)

  • \(对于操作二而言 dp_{i} 无需计算,直接更新mul *= val_{i}\)

  • $对于操作三而言 不管它有多少次调用操作一和操作二 我们都只计算它当下的贡献 也就是 dp_{i} = dp_{i} + mul ,mul *= mul_{i} $

\(想必大家都会有疑问 对于操作三 它明明有可能调用一二两种操作 为什么只计算当下(或者说后面对它的贡献) 不要着急\)

\(我们先想想我们这么做的答案是什么 每个数应该是它总共被乘上了 mul 加上某个数(这个数是加法操作和多次乘法操作的产物(雾))\)

$我们不妨就记每个数加上的数是 add_{i} $

\(然后我们按照拓扑序 依次更新 add_{i} 对于操作一 add_{i} = add_{i} + dp_{i} * val_{i};\)

\(对于三操作 我们更新一下真正的 dp_{i},为了好看 假设我们更新的是dp_{j},其中j是i调用的函数\)

\(那么dp_{j} 等于 dp_{j} + dp_{i} 同时我们的dp_{i}也要更新 因为 我们接下来要遍历j的调用前的函数pre 而dp_{pre} = dp{pre} + dp_{i}\)

\(注意此时因为已经遍历了j 那么调用pre后所有数都乘上了 mul{j},所以我们必须把这个贡献算进去 也就是dp_{i} = dp{i} * mul{j}\)

\(这样做会把我们真正的dp_{i}更新了,我们不需要,所以我们用一个tmp 来代替dp_{i}即可 (tmp 可以理解为是后缀积 (奇奇怪怪的想法))\)

$然后这样我们就把所有数的add_{i} 维护好了 直接输出我们的答案 val_{i} * mul + add_{i} 即可 $

仔细想想 似乎这道题也并非那么难?

代码如下


#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue> 

using namespace std;


const int N = 100010;
const int mod = 998244353; 
#define LL long long
int n,m,x;
int a[N];
int p[N],val[N];
int t[N],c;
int func[N],vis[N],d[N];

LL mu = 1,mul[N],dp[N],add[N];
vector <int> e[N];
queue <int> q;

inline int read()
{
	char ch = getchar();int f = 0,x = 0;
	while(ch > '9' || ch < '0') f |= (ch == '-'),ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch - '0'),ch = getchar();
	if(f) x = -x;return x; 
}


void dfs(int u)
{
	vis[u] = true;
	mul[u] = (t[u] == 2 ? val[u] : 1);
	for(int j : e[u])
	{
		if(!vis[j]) dfs(j);
		mul[u] = mul[j] * mul[u] % mod;
	}
	
}


signed main()
{
	n = read();
	for(register int i = 1; i <= n; ++ i) a[i] = read();
	m = read();
	for(register int i = 1; i <= m; ++ i)
	{
		t[i] = read();
		if(t[i] == 1) p[i] = read(),val[i] = read();
		else if(t[i] == 2) val[i] = read();
		else 
		{
		    c = read();
		    while(c --)
		    {
		        x = read();
		        e[i].push_back(x);
		        d[x] ++;
			}
		}
	}
	c = read();
	for(register int i = 1; i <= c; ++ i) func[i] = read();
	for(register int i = 1; i <= m; ++ i) if(!vis[i] && !d[i]) dfs(i);
    
    for(register int i = c; i >= 1; -- i)
    {
    	int f = func[i];
    	if(t[f] == 1)  dp[f] = (dp[f] + mu);
    	else if(t[f] == 2) mu = (mu * val[f]) % mod;
    	else dp[f] = (dp[f] + mu), mu = (mu * mul[f]) % mod;
	}
	for(register int i = 1; i <= m; ++ i) 
	  if(!d[i]) q.push(i);
	while(q.size())
	{
		int hh = q.front();q.pop();
		if(t[hh] == 1) add[p[hh]] = (add[p[hh]] + dp[hh] * val[hh]) % mod;
	    LL tmp = dp[hh];reverse(e[hh].begin(),e[hh].end());
	    for(int j:e[hh])
	    {
	    	d[j] --;if(!d[j]) q.push(j);
	    	dp[j] = (dp[j] + tmp) % mod,tmp = tmp * mul[j] % mod;
		}
	}
	for(register int i = 1; i <= n; ++ i)cout<<(a[i] * mu + add[i]) % mod<<" ";
	return 0; 
	
}

标签:ch,int,题解,函数调用,add,操作,mul,CSP,dp
来源: https://www.cnblogs.com/yjyl0098/p/15437048.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有