题解:CSP-S2020] 函数调用

  • 一句话题意:给定一个有初始值的序列,支持如下三种操作:

    • 1、单点加
    • 2、全局乘
    • 3、递归某些操作1、2、3
  • 求最终的序列。

  • 标签:topsort,动态规划,转化贡献统计(集中贡献),主客翻转

  • 关于topsort:部分分里的树结构基本上直接暗示了正解要使用topsort,而且本来函数关系就会组成一张DAG。

  • 关于贡献转化

    • 加、乘运算的独立比较容易想到:即某个元素的终值=初值*全局乘因子+扩倍后每个加法因子

      • 简单来说,
\[((a+b)\times c+d)\times e=a \times c \times d+b \times c \times e +d \times e
\]
  • 感觉难点在于想到贡献的统计要全部转化到操作1上

  • 如果针对每个操作统计贡献,那意味着每个操作上要挂原序列中的 \(n\) 个数,显然不管是空间还是时间,这都是无法承受的。而我们可以通过动态规划的方式将所有贡献转到操作1上。(搞了半天精髓还是在动规上!!!)

    • 全局乘因子可以一遍倒序topsort求得
    • 扩倍后每个加法因子可以一遍正序top求得,思想见这篇博客
      • 简单来说就是同父亲的儿子的乘法因子受到更靠右的儿子的影响,链式前向星的遍历顺序天然地满足我们从右到左遍历儿子的需求。
    • 最后合并贡献

    a[b[i].p]=((a[b[i].p]+1ll*b[i].v*b[i].sum)%mod+mod)%mod;

    (存疑:为何还要乘 b[i].v ???sum中没有包含吗?)

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
char buf[100],*p1=buf,*p2=buf;
inline int gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++;}
inline int rd(){
int x=0; char ch;
while(!isdigit(ch=gc()));
do x=(x<<3)+(x<<1)+(ch^48); while(isdigit(ch=gc()));
return x;
}
const int N=1e6+5;
const int mod=998244353;
struct node{
int op,p,v,mul,sum;
}b[N];
struct edge{
int v,ne;
}e[N<<1];
int n,m,q,idx=0,cnt=0;
int in[N],a[N],first[N],ord[N],f[N];
void add(int x,int y){e[++idx]=(edge){y,first[x]};first[x]=idx;}
void topsort(){
queue<int> q;
F(i,1,m) if(!in[i]) q.emplace(i);
while(q.size()){
int u=q.front(); q.pop();
ord[++cnt]=u;
for(int i=first[u];i;i=e[i].ne){
int v=e[i].v;
if(!(--in[v])) q.emplace(v);
}
}
}
void getmul(){
G(o,m,1){
int u=ord[o];
for(int i=first[u];i;i=e[i].ne){
int v=e[i].v;
b[u].mul=(1ll*b[u].mul*b[v].mul)%mod;
// nw=(1ll*nw*b[u].mul)%mod;
}
}
}
void getsum(){
F(o,1,m){
int u=ord[o],nw=1;
for(int i=first[u];i;i=e[i].ne){
int v=e[i].v;
b[v].sum=(1ll*b[v].sum+1ll*nw*b[u].sum)%mod;
nw=(1ll*nw*b[v].mul)%mod;
}
}
}
signed main(){
n=rd();
F(i,1,n) a[i]=rd();
m=rd();
F(i,1,m){
b[i].op=rd();
if(b[i].op==1){
b[i].p=rd(),b[i].v=rd();
b[i].mul=1;
}
else if(b[i].op==2){
b[i].v=rd();
b[i].mul=b[i].v;
}
else{
b[i].p=rd();
b[i].mul=1;
F(j,1,b[i].p){
int o=rd();
add(i,o);
in[o]++;
}
}
}
topsort();
getmul();
q=rd(); int nw=1;
F(i,1,q) f[i]=rd();
G(i,q,1){
int x=f[i];
b[x].sum=(b[x].sum+1ll*nw)%mod;
nw=(1ll*nw*b[x].mul)%mod;
}
getsum();
F(i,1,n) a[i]=(1ll*a[i]*nw)%mod;
F(i,1,m){
if(b[i].op==1){
a[b[i].p]=((a[b[i].p]+1ll*b[i].v*b[i].sum)%mod+mod)%mod;
}
}
F(i,1,n) printf("%d ",a[i]);
return 0;
}
  • 总结:答案贡献分散,难以统计时,考虑转化统计主体,以集中贡献,优化算法。

题解:CSP-S2020] 函数调用的更多相关文章

  1. [CSP-S 2019 day2 T2] 划分

    题面 题解 CSP赛场上能请教别人吗 在这道题中,我看到了一个很敏感又很熟悉的东西--平方! 这意味着,可以推出一些结论,使这道题几乎可以边输入边解决. 自己在脑子里动态一下就知道,像这种总和一定.代 ...

  2. 2019 CSP J/S第2轮 视频与题解

    CSP入门组和提高组第二轮题解 转自网络

  3. 上午小测3 T1 括号序列 && luogu P5658 [CSP/S 2019 D1T2] 括号树 题解

    前 言: 一直很想写这道括号树..毕竟是在去年折磨了我4个小时的题.... 上午小测3 T1 括号序列 前言: 原来这题是个dp啊...这几天出了好几道dp,我都没看出来,我竟然折磨菜. 考试的时候先 ...

  4. [CSP模拟测试43、44]题解

    状态极差的两场.感觉现在自己的思维方式很是有问题. (但愿今天考试开始的一刻我不会看到H I J) A 考场上打了最短路+贪心,水了60. 然而正解其实比那30分贪心好想多了. 进行n次乘法后的结果一 ...

  5. 题解 nflsoj489 【六校联合训练 CSP #15】小D与随机

    题目链接 考虑枚举好点的集合.此时要考虑的问题是如何填入\(1\sim n\)这些数使得恰好我们枚举到的这些点是好点,即:求出有多少种合法的填数方案. \(1\)号点一定是好点.那么除\(1\)号点外 ...

  6. C++对象模型的那些事儿之六:成员函数调用方式

    前言 C++的成员函数分为静态函数.非静态函数和虚函数三种,在本系列文章中,多处提到static和non-static不影响对象占用的内存,而虚函数需要引入虚指针,所以需要调整对象的内存布局.既然已经 ...

  7. CSP应用开发-CryptAPI函数库介绍

    基本加密函数为开发加密应用程序提供了足够灵活的空间.所有CSP的通讯都是通过这些函数.一个CSP是实现所有加密操作的独立模块.在每一个应用程序中至少需要提供一个CSP来完成所需的加密操作.如果使用多于 ...

  8. 算法(第四版)C# 习题题解——2.3

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 查找更为方便的版本见:http ...

  9. CCF CSP 201703-3 Markdown

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201703-3 Markdown 问题描述 Markdown 是一种很流行的轻量级标记语言(l ...

  10. CCF计算机职业资格认证考试题解

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF计算机职业资格认证考试题解 CCF计算机软件能力认证(简称CCF CSP认证)是CCF计算机职业资格认证系 ...

随机推荐

  1. @RequestBody中传递json里的对象,对象包含list属性,对应body里的格式

    以下就是对应格式,直接复制进接口文档相关工具即可{ "userId": "88", "openCostCenterDTO": [ { &qu ...

  2. grpc坑之Could not find TLS ALPN provider; no working netty-tcnative

    在使用grpc过程中偶尔会遇到下面报错: Initialization of bean failed; nestedexception is java.lang.IllegalStateExcepti ...

  3. 8. 从0学ARM-内联汇编、混合汇编、ATPCS规则

    一.gcc 内联汇编 内联汇编即在C中直接使用汇编语句进行编程,使程序可以在C程序中实现C语言不能完成的一些工作,例如,在下面几种情况中必须使用内联汇编或嵌入型汇编. 程序中使用饱和算术运算(Satu ...

  4. .NET 智能组件完全开源

    Daniel Roth在2024年3月20日发布了一篇文章: .NET 智能组件简介 – AI 驱动的 UI 控件.文章主要介绍了.NET Smart Components,这是一系列可以快速轻松地添 ...

  5. Oracle数据库自动备份

    1.bat脚本 格式为ANSI格式 set CURDATE=%date:~0,4%%date:~5,2%%date:~8,2% set CURMON=%date:~0,4%%date:~5,2% se ...

  6. LaTeX 交叉引用的四次编译

    编译包含交叉引用的 LaTeX 文件需要编译四次(pdflatex + bibtex + pdflatex * 2),一直对这四次编译都干了什么事很好奇.这次就来看一下每一步具体都干了些什么. 源文件 ...

  7. 如何使用ChatGPT自带插件

    OpenAI的插件将ChatGPT连接到第三方应用程序.这些插件使ChatGPT能够与开发者定义的API进行交互,增强ChatGPT的能力,并使其能够执行广泛的操作.插件使ChatGPT能够做如下事情 ...

  8. hexo使用小技巧

    1.在博客中加入图片 使用语法 {% asset_img 1.jpg %} 这样hexo会自动渲染1.jpg.,然后1.jpg的位置需要放在同文件名的文件夹中,比如这篇博客叫hexo使用小技巧,那么这 ...

  9. 深度学习批次(batch)、迭代(iteration)、周期(epoch)、前向传播(forward propagation)、反向传播(backward propagation)、学习率(learning rate)概念解释

    虽然现在应该是已经熟练掌握这些基础概念的时候,但是我是鱼的记忆,上一秒的事情,下一秒就忘了,除非是重要的人的重要的事情,呜呜呜呜,我这个破脑子. 还是写一下吧,直接GPT出来的(人类之光,欢呼~). ...

  10. 基于语义增强的少样本检测,突破新类别偏见 | ICIP'24

    Few-shot目标检测(FSOD)旨在在有限标注实例的情况下检测新颖对象,在近年取得了显著进展.然而,现有方法仍然存在偏见表示问题,特别是在极低标注情况下的新颖类别.在微调过程中,一种新颖类别可能会 ...