题解: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. PHP转Go系列 | ThinkPHP与Gin框架之打造基于WebSocket技术的消息推送中心

    大家好,我是码农先森. 在早些年前客户端想要实时获取到最新消息,都是使用定时长轮询的方式,不断的从服务器上获取数据,这种粗暴的骚操作实属不雅.不过现如今我也还见有人还在一些场景下使用,比如在 PC 端 ...

  2. 【粉丝问答20】Linux内核定时器使用及其他时间操作

    问题描述 如何使用内核定时器? 内核定时器 Linux内核定时器是timer_list,下面我们详细介绍定时器的使用. 1. 简介 内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执 ...

  3. 痞子衡嵌入式:英飞凌MirrorBit工艺NOR Flash的扇区架构设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是英飞凌MirrorBit工艺NOR Flash的扇区架构设计. NOR Flash 大家都很熟悉,其内部按组织从小到大分为 Page(12 ...

  4. Kubernetes 初学部署遇到的问题

    ### Kubernetes 部署文档(CentOS 7.9) 本文采用centos9 截至2024年8月21日官网已经不再提供其他下载 直接用最新版即可 1. CentOS 7.9 内核版本问题 截 ...

  5. 操作 JAR 文件

    列出 JAR 文件内容 使用 jar 命令来列出 JAR 文件的内容: jar tf myapp.jar -t 选项表示列出文件,-f 表示指定 JAR 文件. 解压 JAR 文件 使用 jar 命令 ...

  6. APT 使用

    使用 Ubuntu 包搜索器 apt 命令 功能 apt install 安装软件包 apt remove 移除软件包 apt purge 移除软件包及配置文件 apt update 刷新存储库索引 ...

  7. Unity 刚体 AddForce 的几种力类型

    今天在实现 2D 横版跳跃的时候,发现使用AddForce添加的力太突兀了,没有逐渐向上的过程,发现AddForce还有ForceMode mode参数 以下部分内容摘自Bing Copilot总结 ...

  8. CSS & JS Effect – Image hover animation

    效果 效果来自: webflow 的一个模板 需求解释 有 3 给元素, 图片, overlay(黑影), link mouse enter 的时候, 图片要 zoom in. overlay 要 f ...

  9. Python 潮流周刊#69:是时候停止使用 Python 3.8了(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  10. 【Abyss】Android 平台应用级系统调用拦截框架

    Android平台从上到下,无需ROOT/解锁/刷机,应用级拦截框架的最后一环 -- SVC系统调用拦截. ☞ Github ☜ 由于我们虚拟化产品的需求,需要支持在普通的Android手机运行.我们 ...