【题解】[CSP-S2020] 函数调用

[CSP-S2020] 函数调用

( ext{Solution:})

看题要冷静……

首先要看到的是,函数调用之间形成了图的关系。先考虑一个暴力的办法:

建好图,按照顺序,然后走的时候暴力用全局记录标记维护修改,直接 DAG 上跑

大概这样可以得到 (75 o 85) 的分数。

因为有 (0) 的存在。所以需要特判,懒一点用 memset 可以有 (75) 分。

那么考虑如何优化。

首先,优化的第一点就是不能每次都到图上去跑。那怎么办?考虑处理出每一个函数的影响。

我们发现,对于 (3) 函数的影响,好像还需要合并一些单点上的值,很难维护……

那能不能把这种操作的影响直接划分到每一个小函数上?

于是我们就发现,对于 (mul=k) 的函数而言,意味着它前面所有函数的调用次数都变成了 (k) 次。

于是我们考虑建立反图,直接把每一个函数对应的调用次数跑出来。

这样就可以 (O(n)) 了。注意一下细节:

对于一个函数而言,其乘法影响的只有 topo 在它后面的点的 (cnt,) 对在同一层的函数是没有影响的。所以我们考虑倒着做,遇到 (0) 就可以舍弃了。

而递推乘法标记的时候,需要用反图来递推;递推函数次数的时候就要用原图递推了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline int Abs(int x){if(x<0)x=-x;return x;}
inline int Add(int x,int y){return (x+y)%mod;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline int Dec(int x,int y){return (x-y+mod)%mod;}
const int N=2e5+10;
vector<int>G[N];
vector<int>F[N];
int mul[N],opt[N],pos[N],val[N];
int Q,a[N],n,m,in[N],fin[N];
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=Mul(res,x);
		x=Mul(x,x);y>>=1;
	}
	return res;
}
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
queue<int>q;
int cnt[N];
inline int getinv(int x){return qpow(x,mod-2);}
void Topo(int op){
	while(!q.empty())q.pop();
	if(op==1){
		for(int i=0;i<=m;++i){
			in[i]=G[i].size();
			if(!in[i])q.push(i);
		}
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(int j:F[x]){
				in[j]--;
				mul[j]=Mul(mul[j],mul[x]);
				if(!in[j])q.push(j);
			}
		}
	}
	else{
		for(int i=0;i<=m;++i){
			fin[i]=F[i].size();
			if(!fin[i])q.push(i);
		}
		for(int i=0;i<=m;++i)reverse(G[i].begin(),G[i].end());
		while(!q.empty()){
			int x=q.front();
			q.pop();
			int Multg=1;
			for(auto v:G[x]){
				cnt[v]=Add(cnt[v],Mul(cnt[x],Multg));
				Multg=Mul(Multg,mul[v]);
				fin[v]--;
				if(!fin[v])q.push(v);
			}
		}
	}
}
void calc(){
	for(int i=1;i<=m;++i){
		if(opt[i]==2)continue;
		if(opt[i]==3)continue;
		a[pos[i]]=Add(a[pos[i]],Mul(cnt[i],val[i]));
		printf("%d : %d
",i,cnt[i]);
	}
	for(int i=1;i<=n;++i)printf("%lld ",a[i]);
}
signed main(){
	freopen("in.txt","r",stdin);
	n=read();
	for(int i=1;i<=n;++i)a[i]=read();
	m=read();
	for(int i=0;i<=m;++i)mul[i]=1;
	for(int i=1;i<=m;++i){
		opt[i]=read();
		if(opt[i]==1){pos[i]=read();val[i]=read();}
		if(opt[i]==2){mul[i]=read();}
		if(opt[i]==3){
			int num=read();
			for(int ii=1;ii<=num;++ii){
				int vv=read();
				G[i].push_back(vv);
				F[vv].push_back(i);
			}
		}
	}
	Q=read();
	cnt[0]=1;
	while(Q--){
		int stt=read();
		G[0].push_back(stt);
		F[stt].push_back(0);
	}
	Topo(1);
	printf("%d
",mul[0]);
	Topo(2);
	
	for(int i=1;i<=n;++i)a[i]=Mul(a[i],mul[0]);
	calc();
	return 0;
}
原文地址:https://www.cnblogs.com/h-lka/p/15353473.html