• CSP-S 2020


    ( ext{Solution})

    其实并不是一道难题,只是不知道如何一步步算。

    首先想算出每个 (1) 操作的系数,这样能省去很多重复步骤。

    观察到 (1) 操作可以被分成单个函数(指直接出现在函数操作序列中)和被引用函数(被直接出现在函数操作序列中的第 (3) 类函数引用)。

    对于每个(一种函数可能在函数操作序列中被直接调用多次)单个函数我们需要算出在调用它之后调用的 (2) 操作之积,显然这就是对于这个单个函数的系数。我们将这种函数的每个单个函数的系数相加,显然就是这种函数的单个函数的总系数。

    那被引用函数呢?我们只要向上面那样,算出第 (3) 类函数的系数,再下传给它就好了(注意这是一个 ( ext{DAG}),所以用拓扑排序来下传)。

    详见注释。

    ( ext{Code})

    #include <cstdio>
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define print(x,y) write(x),putchar(y)
    
    int read() {
    	int x=0,f=1; char s;
    	while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    	while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    	return x*f;
    }
    
    void write(int x) {
    	if(x<0) return (void)(putchar('-'),write(-x));
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <queue>
    #include <vector>
    using namespace std;
    
    const int maxn=1e5+5,mod=998244353;
    
    int n,m,Q,a[maxn],op[maxn],pos[maxn],val[maxn],id[maxn],deg[maxn],mul[maxn],Add[maxn],f[maxn];
    vector <int> g[maxn];
    queue <int> q;
    bool vis[maxn];
    
    void dfs(int u) {
    	if(vis[u]) return;
    	vis[u]=1;
    	mul[u]=(op[u]==2?val[u]:1); // mul: 直接引用第 3 类函数会导致翻多少倍
    	for(int i=0;i<g[u].size();++i) {
    		int v=g[u][i];
    		dfs(v);
    		mul[u]=1ll*mul[u]*mul[v]%mod;
    	}
    }
    
    void topol() {
    	int Mul;
    	rep(i,1,m) if(!deg[i]) q.push(i);
    	while(!q.empty()) {
    		int u=q.front(); q.pop();
    		if(op[u]==1) Add[pos[u]]=(Add[pos[u]]+1ll*f[u]*val[u]%mod)%mod; // 注意不能在后面插入队列时更新,不然本来就无子的就无法更新
    		Mul=f[u];
    		for(int i=g[u].size()-1;i>=0;--i) {
    			int v=g[u][i];
    			--deg[v];
    			if(!deg[v]) q.push(v);
    			f[v]=(f[v]+Mul)%mod; Mul=1ll*Mul*mul[v]%mod; // 这里是为了算间接引用时 v 的贡献:父亲们的系数 * 在自己后面的兄弟的系数
    		}
    	} 
    }
    
    int main() {
    	int x,y;
    	n=read();
    	rep(i,1,n) a[i]=read();
    	m=read();
    	rep(i,1,m) {
    		op[i]=read();
    		if(op[i]==1) pos[i]=read(),val[i]=read();
    		else if(op[i]==2) val[i]=read();
    		else {
    			x=read();
    			rep(j,1,x) y=read(),++deg[y],g[i].push_back(y);
    		}
    	}
    	Q=read();
    	rep(i,1,Q) id[i]=read();
    	rep(i,1,m) if(!deg[i]) dfs(i);
    	y=1;
    	for(int i=Q;i>=1;--i) {
    		x=id[i];
    		if(op[x]==1) f[x]=(f[x]+y)%mod;
    		else if(op[x]==2) y=1ll*y*mul[x]%mod;
    		else f[x]=(f[x]+y)%mod,y=1ll*y*mul[x]%mod; // f 就是算函数在函数调用序列里翻了多少倍
    	}
    	topol();
    	rep(i,1,n) print((1ll*a[i]*y%mod+Add[i])%mod,' '); puts("");
    	return 0;
    }
    
  • 相关阅读:
    java_IO读写模版
    c#_DropdownList Panel Textbox 控件交互使用,有autopostback和没有的区别
    C#_datatable 写入大量数据_BulkCopy
    C#_datatable_读取
    C#_数据库交互_SqlHelper
    C#_数据库基本交互
    C#_Wpf_DataContex上下文整个类绑定
    C#_wpf_userinput_数据绑定_后台对象改变,界面数据也变化
    C#_delegate
    C#_delegate
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14022221.html
Copyright © 2020-2023  润新知