[lnsyoj446/luoguP7077/CSP-S 2020] 函数调用

原题链接

sol

将结果拆为 ansi=aimult+adi,其中 mult 为进行的乘法操作的总贡献,adi 为加法操作对第 i 个数的贡献。
如果没有函数 3 的话,mult 即为调用的所有函数 2 参数的积,并且容易发现,在调用了一次函数 2 之后,前面所有的函数 1 的贡献也会乘上其参数,因此可以计算出 fi 表示函数 1 贡献的系数,fi 可以倒着进行计算。
考虑函数 3,由于没有递归操作,因此会形成一个 DAG,容易想到没有后效性的拓扑排序。
因此,先按照操作序列倒序枚举,计算 multfi,再根据拓扑序更新 fiadi 即可,具体见代码

代码

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

using namespace std;
typedef long long LL;

const int N = 100005, M = N, mod = 998244353;

vector<int> ne[N];
int a[N], V[N], pos[N], mul[N], ad[N], typ[N], outd[N];
int f[N];
int n, m, q, d[N];
bool st[N];

void dfs(int u){
    if (st[u]) return ;
    st[u] = true;
    if (typ[u] == 2) mul[u] = V[u];
    else mul[u] = 1;
    for (auto x : ne[u]) {
        dfs(x);
        mul[u] = (LL) mul[u] * mul[x] % mod;
    }
}

int main(){
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    scanf("%d", &m);
    for (int i = 1; i <= m; i ++ ) {
        scanf("%d", &typ[i]);
        if (typ[i] == 1) scanf("%d%d", &pos[i], &V[i]);
        else if (typ[i] == 2) scanf("%d", &V[i]);
        else {
            int g;
            scanf("%d", &g);
            while (g -- ){
                int t;
                scanf("%d", &t);
                ne[i].push_back(t);
                outd[t] ++ ;
            }
        }
    }
    
    queue<int> que;
    for (int i = 1; i <= m; i ++ ) 
        if (!st[i] && !outd[i]) dfs(i), que.push(i);
    scanf("%d", &q);
    for (int i = 1; i <= q; i ++ ) scanf("%d", &d[i]);

    int mult = 1;
    for (int i = q; i; i -- ){
        if (typ[d[i]] == 1) f[d[i]] = (f[d[i]] + mult) % mod;
        else if (typ[d[i]] == 2) mult = (LL) mult * V[d[i]] % mod;
        else f[d[i]] = (f[d[i]] + mult) % mod, mult = (LL) mult * mul[d[i]] % mod;
    }

    while (!que.empty()) {
        int t = que.front();
        que.pop();
        if (typ[t] == 1) ad[pos[t]] = (ad[pos[t]] + (LL) f[t] * V[t] % mod) % mod;
        if (typ[t] == 3) {
            int temp = f[t];
            for (int i = ne[t].size() - 1; i >= 0; i -- ){
                int j = ne[t][i];
                f[j] = (f[j] + temp) % mod;
                temp = (LL) temp * mul[j] % mod;
                outd[j] -- ;
                if (!outd[j]) que.push(j);
            }
        }
    }

    for (int i = 1; i <= n; i ++ ) printf("%lld ", ((LL) a[i] * mult % mod + ad[i]) % mod);
}

蒟蒻犯的若至错误

  • nm 混淆
posted @   是一只小蒟蒻呀  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示