loj3381. 「CSP-S 2020」函数调用

题目链接

诈骗题。看起来很像数据结构,事实上是个图论。

题目明确说明调用关系是一个 DAG,考虑拓扑排序。

不难发现乘法的本质上是将加法操作重复了若干次,于是我们可以考虑把所有操作都转化为加法操作。

每个加法的贡献次数是他后面所有乘法操作的乘积,我们可以直接在 DAG 上面 dp 出每一个 3 类型函数内部执行到第 \(i\) 个调用的时候的乘法操作后缀积,然后再拓扑排序求出每个加法操作在这个序列里面会被执行多少次,然后直接把贡献加到变量上面就好了。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#define int long long
const int mod=998244353;
struct function
{
    int opt,pos,val;
    vector<int> son;
}fun[1000001];
int n,m,p,a[1000001],d[1000001],sum[1000001];
vector<int> f[1000001],v[1000001];
bool vis[1000001];
inline int read()
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x;
}
void print(int x)
{
    if(x>=10)
        print(x/10);
    putchar(x%10+'0');
}
inline void dfs(int k)
{
    vis[k]=1;
    if(fun[k].opt==1)
    {
        f[k].push_back(1);
        f[k].push_back(1);
        return;
    }
    if(fun[k].opt==2)
    {
        f[k].push_back(fun[k].val);
        f[k].push_back(1);
        return;
    }
    for(auto i:fun[k].son)
    {
        if(!vis[i])
            dfs(i);
        f[k].push_back(f[i][0]);
    }
    for(register int i=f[k].size()-2;~i;--i)
        f[k][i]=f[k][i]*f[k][i+1]%mod;
    f[k].push_back(1);
}
inline void topo()
{
    sum[m]=1;
    queue<int> q;
    for(register int i=1;i<=m;++i)
        if(!d[i])
            q.push(i);
    while(!q.empty())
    {
        int k=q.front();
        q.pop();
        int j=0;
        for(auto i:fun[k].son)
        {
            ++j;
            if(!--d[i])
                q.push(i);
            if(!vis[k])
                continue;
            sum[i]=(sum[i]+sum[k]*f[k][j]%mod)%mod;
        }
    }
}
signed main()
{
    n=read();
    for(register int i=1;i<=n;++i)
        a[i]=read();
    m=read();
    for(register int i=1;i<=m;++i)
    {
        fun[i].opt=read();
        if(fun[i].opt==1)
            fun[i].pos=read(),fun[i].val=read();
        if(fun[i].opt==2)
            fun[i].val=read();
        if(fun[i].opt==3)
        {
            p=read();
            while(p--)
            {
                fun[i].son.push_back(read());
                ++d[fun[i].son.back()];
            }
        }
    }
    p=read();
    ++m;
    for(register int i=1;i<=p;++i)
    {
        fun[m].son.push_back(read());
        ++d[fun[m].son.back()];
    }
    dfs(m);
    topo();
    for(register int i=1;i<=n;++i)
        a[i]=(a[i]*f[m][0])%mod;
    for(register int i=1;i<=m;++i)
        if(fun[i].opt==1)
            a[fun[i].pos]=(a[fun[i].pos]+sum[i]*fun[i].val%mod)%mod;
    for(register int i=1;i<=n;++i)
    {
        print(a[i]);
        putchar(' ');
    }
    puts("");
    return 0;
}
posted @ 2021-09-29 22:06  绝顶我为峰  阅读(59)  评论(0编辑  收藏  举报