【题解】[CSP-S2020] 函数调用
看题要冷静……
首先要看到的是,函数调用之间形成了图的关系。先考虑一个暴力的办法:
、
建好图,按照顺序,然后走的时候暴力用全局记录标记维护修改,直接 DAG 上跑
大概这样可以得到 的分数。
因为有 的存在。所以需要特判,懒一点用 memset
可以有 分。
那么考虑如何优化。
首先,优化的第一点就是不能每次都到图上去跑。那怎么办?考虑处理出每一个函数的影响。
我们发现,对于 函数的影响,好像还需要合并一些单点上的值,很难维护……
那能不能把这种操作的影响直接划分到每一个小函数上?
于是我们就发现,对于 的函数而言,意味着它前面所有函数的调用次数都变成了 次。
于是我们考虑建立反图,直接把每一个函数对应的调用次数跑出来。
这样就可以 了。注意一下细节:
对于一个函数而言,其乘法影响的只有 topo 在它后面的点的 对在同一层的函数是没有影响的。所以我们考虑倒着做,遇到 就可以舍弃了。
而递推乘法标记的时候,需要用反图来递推;递推函数次数的时候就要用原图递推了。
#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\n",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\n",mul[0]);
Topo(2);
for(int i=1;i<=n;++i)a[i]=Mul(a[i],mul[0]);
calc();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?