Atcoder ABC387F Count Arrays 题解 [ 绿 ] [ 基环树 ] [ 树形 dp ] [ 前缀和优化 ]

news/2025/1/12 11:36:45/文章来源:https://www.cnblogs.com/zhr0102/p/18666804

Count Arrays:一眼秒的计数题。

思路

显然,把小于等于的条件化为大的向小的连单向边,每个数的入度都是 \(1\),就会形成一个基环树森林。

那么考虑这个环上能填什么数。因为所有数都小于等于他后面的数,所以所有数都只能相等。这就启发我们在基环树上缩点之后再进行计数。

那么当缩完点计数时如何计算呢?有个很简单的 dp,定义 \(dp_{i,j}\) 表示考虑到节点 \(i\),节点 \(i\)\(j\) 的方案数,则很容易能写出转移:

\[dp_{i,j}=\prod_{k=1}^{\left|son_i\right|}(\sum_{a=1}^{j}dp_{son_{i,k},a}) \]

直接转移是 \(O(nm^2)\) 的,前缀和优化即可做到 \(O(nm)\)

答案计算时将所有基环树的答案乘起来即可。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
using pii=pair<int,pi>;
const ll mod=998244353;
int n,m,a[10005];
int dfn[10005],low[10005],stk[10005],cnt=0,tp=0,scc[10005],tot=0;
bitset<10005>instk,vis,rd;
vector<int>g[10005],tr[10005];
ll ans=1,dp[3005][3005],f[3005][3005];
void tarjan(int u)
{dfn[u]=low[u]=++tot;instk[u]=1,stk[++tp]=u;for(auto v:g[u]){if(dfn[v]==0){tarjan(v);low[u]=min(low[u],low[v]);}else if(instk[v]){low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]){int now;cnt++;do{now=stk[tp--];instk[now]=0;scc[now]=cnt;}while(now!=u);}
}
void dfs(int u)
{for(int i=1;i<=m;i++)dp[u][i]=1;for(auto v:tr[u]){dfs(v);for(int i=1;i<=m;i++){dp[u][i]=(dp[u][i]*f[v][i])%mod;}}for(int i=1;i<=m;i++)f[u][i]=(f[u][i-1]+dp[u][i])%mod;
}
int main()
{//freopen("sample.in","r",stdin);//freopen("sample.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];g[a[i]].pb(i);}for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i);for(int i=1;i<=n;i++){int fu=scc[i];for(auto v:g[i]){int fv=scc[v];if(fu!=fv){tr[fu].pb(fv);rd[fv]=1;}}}for(int i=1;i<=cnt;i++){if(rd[i]==0){dfs(i);ans=(ans*f[i][m])%mod;}}cout<<ans;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/868105.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bullyBox pg walkthrough Intermediate

nmap 发现80 和 22端口 访问80 端口发现 跳转 http://bullybox.local/ 在/etc/hosts 里面加上这个域名dirsearch 扫描的时候发现了.git泄露 用dunpall工具 获取.git泄露的源码查看源码 我们发现了数据库的密码 name => boxbilling, user => admin, password => Playin…

苹果系统下无痕检测是否开启iMessage服务,iMessages数据筛选,iMessage蓝号检测协议版

一、实现iMessage数据检测的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2…

数据分析之年度总结分享

背景:我们是一家国内的服装公司,在全国拥有几十家服装门店,从事18个服装品类的销售,市场覆盖国内上海、华北、华中、西南、东北、中南、西北七个区域,年销售额达数千万元。财年结束了,老板希望我们(数据分析师)能对公司的销售团队的数据进行分析,并得出结论作为下年度…

国家数据如何统一目录标识、统一身份登记和统一接口

日前,《国家数据基础设施建设指引》发布。最大的看点之一,是全国数据统一大市场:统一目录标识、统一身份登记和统一接口。那么,如何实现数据的全国统一目录标识、统一身份登记和统一接口? 一、全国统一目录标识 建立数据分类标准 顶层设计规划:由国家相关部门牵头,联合各…

信创环境下国产系统不同版本的依赖库都从哪里下载

在Linux系统中安装软件时,可能会遇到各种依赖库问题,以下是一些常见的依赖库问题及其解决方法,以及获取软件依赖包的不同途径。 1、依赖库问题 依赖库版本不兼容:安装软件时,系统提示缺少特定版本的依赖库。 依赖库缺失:软件安装需要某些库文件,但系统中未安装。 依赖冲…

1. 结构光系统标定原理

什么时逆向机法,与双目模型区别?

读量子霸权01硅时代的终结

硅时代的终结1. 量子计算机 1.1. 一种全新型计算机,在处理特定任务时能明显超越普通数字超级计算机1.1.1. 谷歌宣称自己研发的量子计算机Sycamore可以在200秒以内解决世界上最快的数字超级计算机花1万年才能完成的数学问题1.1.1.1. 谷歌的Sycamore量子计算机就是全球第一台实现…

合成橡胶 2025

1月12日: C浪反弹进行中 目前在走C-3

转:celery 常用执行命令

转自:https://blog.csdn.net/weixin_44649870/article/details/105844668celery 常用执行命令详解执行命令celery -A test-1.celery worker -n name-1 --loglevel=info --max-tasks-per-child 500 --autoscale=4,1 -Q q-1常用参数参数 说明-A / --app 要使用的应用程序实例-n …

VMware ESXi 8.0U3c macOS Unlocker OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动

VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成驱动版,新增 12 款 I219 网卡驱动 VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版…