1. 程式人生 > 實用技巧 >LG P7077 函式呼叫

LG P7077 函式呼叫

Description

函式是各種程式語言中一項重要的概念,藉助函式,我們總可以將複雜的任務分解成一個個相對簡單的子任務,直到細化為十分簡單的基礎操作,從而使程式碼的組織更加嚴密、更加有條理。然而,過多的函式呼叫也會導致額外的開銷,影響程式的執行效率。

某資料庫應用程式提供了若干函式用以維護資料。已知這些函式的功能可分為三類:

  1. 將資料中的指定元素加上一個值;
  2. 將資料中的每一個元素乘以一個相同值;
  3. 依次執行若干次函式呼叫,保證不會出現遞迴(即不會直接或間接地呼叫本身)。

在使用該資料庫應用時,使用者可一次性輸入要呼叫的函式序列(一個函式可能被呼叫多次),在依次執行完序列中的函式後,系統中的資料被加以更新。某一天,小 A 在應用該資料庫程式處理資料時遇到了困難:由於頻繁而低效的函式呼叫,系統在執行操作時進入了無響應的狀態,他只好強制結束了資料庫程式。為了計算出正確資料,小 A 查閱了軟體的文件,瞭解到每個函式的具體功能資訊,現在他想請你根據這些資訊幫他計算出更新後的資料應該是多少。

Solution

顯然先進行的加操作會受到之後的乘操作的影響

所以先將每一個操作(包括型別3)的乘法系數算出來

考慮每個加操作的係數就是其之後的所有乘操作乘積,型別3中加操作也會受到內部其之後的乘操作的影響

先對每個型別3建圖,由它自己的編號連向子函式的編號,在DAG上DP就可以求出型別3的係數

接著從後向前掃描可以求出所有單個加操作的係數

最後考慮型別3中加操作

在剛剛的DAG上拓撲排序,按次序更新每個操作的所有子函式係數,遍歷邊時需要逆序

最後對所有加操作更新a數列

#include<iostream>
#include<cstdio>
#include<queue>
using
namespace std; int n,m,t[100005],p[100005],tot,head[100005],du[100005],Q,f[100005]; long long a[100005],add[100005],mul[100005],s=1,cnt[100005]; bool vst[100005]; const int mod=998244353; struct Edge { int to,nxt; }edge[1000005]; queue<int>q; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') {
if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } long long dfs(int k) { if(vst[k]) return mul[k]; vst[k]=true; for(int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; (mul[k]*=dfs(v))%=mod; } return mul[k]; } void topo() { for(int i=1;i<=m;i++) if(!du[i]) q.push(i); while(q.size()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=edge[i].nxt) { int v=edge[i].to; (cnt[v]+=cnt[u])%=mod; (cnt[u]*=mul[v])%=mod; --du[v]; if(!du[v]) q.push(v); } } } int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(); m=read(); for(int i=1;i<=m;i++) { t[i]=read(),mul[i]=1; if(t[i]==1) p[i]=read(),add[i]=read(); else if(t[i]==2) mul[i]=read(); else { int c=read(); for(int j=1;j<=c;j++) { int g=read(); edge[++tot]=(Edge){g,head[i]},head[i]=tot; ++du[g]; } } } for(int i=1;i<=m;i++) { if(!vst[i]) dfs(i); } Q=read(); for(int i=1;i<=Q;i++) f[i]=read(); for(int i=Q;i;i--) { (cnt[f[i]]+=s)%=mod; (s*=mul[f[i]])%=mod; } for(int i=1;i<=n;i++) (a[i]*=s)%=mod; topo(); for(int i=1;i<=m;i++) if(t[i]==1) (a[p[i]]+=add[i]*cnt[i]%mod)%=mod; for(int i=1;i<=n;i++) printf("%lld ",a[i]); return 0; }
函式呼叫