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;
}

Atcoder ABC387F Count Arrays 题解 [ 绿 ] [ 基环树 ] [ 树形 dp ] [ 前缀和优化 ]的更多相关文章

  1. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

  2. HDU6403 Card Game【基环树 + 树形DP】

    HDU6403 Card Game 题意: 给出\(N\)张卡片,卡片正反两面都有数字,现在要翻转一些卡片使得所有卡片的正面的值各不相同,问最小翻转次数和最小翻转情况下的不同方案数 \(N\le 10 ...

  3. 骑士 HYSBZ - 1040(基环树+树形dp)

    Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...

  4. BZOJ 1040 骑士 基环树 树形DP

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目大意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫 ...

  5. bzoj 1040: [ZJOI2008]骑士【基环树+树形dp】

    没考虑可以连着两个不选--直接染色了 实际上是基环森林,对于每棵基环树,dfs找出一个环边,然后断掉这条边,分别对这条边的两端点做一边treedp,取max加进答案里 treedp是设f[u]为选u点 ...

  6. BZOJ 1040 [ZJOI2008]骑士 (基环树+树形DP)

    <题目链接> 题目大意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的 ...

  7. 4.13 省选模拟赛 树 树形dp 卷积 NTT优化dp.

    考试的时候 看到概率 看到期望我就怂 推了一波矩阵树推自闭了 发现 边权点权的什么也不是. 想到了树形dp 维护所有边的断开情况 然后发现数联通块的和再k次方过于困难. 这个时候 应该仔细观察一下 和 ...

  8. BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】

    题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...

  9. day 2 下午 骑士 基环树+树形DP

    #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #inc ...

  10. 51nod 1353 树 | 树形DP经典题!

    51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...

随机推荐

  1. linux之Zip

    安装: apt-get) apt-get install zip yum) yum install -y unzip zip 语法: zip [选项] 压缩包名 源文件或源目录列表 注意,zip 压缩 ...

  2. 借助AI助手如何高效排查SQL问题

    快乐的时光总是转瞬即逝,尤其是当我们面对bug时,不仅浪费了宝贵的时间,更让人感到沮丧.因为bug往往是非常奇怪.难以捉摸的,找来找去你始终无法确定问题所在,最终意识到这些bug并没有多大技术含量.尽 ...

  3. Postman 汉化教程

    Postman 汉化教程(Postman中文版) 迷恋自留地 postman官网下载地址 https://www.postman.com/downloads/ postman汉化包 https://g ...

  4. zz 为什么我更喜欢 Python 的 Storm ORM

    为什么我更喜欢 Python 的 Storm ORM - @emacsway 的博客 很有意思的讨论.可能还是 mapping 比较实用. 另外,文中称赞有加的 Identity Map 并不适合并发 ...

  5. docker.sock: connect: permission denied 解决

    问题描述xjun@DESKTOP-L2R4GKN:~$ docker run -it hello-worlddocker: Got permission denied while trying to ...

  6. rsync+ssh同步备份文件

    定期对web代码或重要的文件做同步异地服务器备份,防止服务器故障严重磁盘损坏时文件丢失的问题. 备份服务器:192.168.200.134 目标服务器:192.168.201.65 rsync同步命令 ...

  7. Qt/C++音视频开发78-获取本地摄像头支持的分辨率/帧率/格式等信息/mjpeg/yuyv/h264

    一.前言 上一篇文章讲到用ffmpeg命令方式执行打印到日志输出,可以拿到本地摄像头设备信息,顺藤摸瓜,发现可以通过执行 ffmpeg -f dshow -list_options true -i v ...

  8. Qt/C++音视频开发59-使用mdk-sdk组件/原qtav作者力作/性能凶残/超级跨平台

    一.前言 最近一个月一直在研究mdk-sdk音视频组件,这个组件是原qtav作者的最新力作,提供了各种各样的示例demo,不仅限于支持C++,其他各种比如java/flutter/web/androi ...

  9. Qt开源作品36-程序守护进程

    一.前言 没有任何人敢保证自己写的程序没有任何BUG,尤其是在商业项目中,程序量越大,复杂度越高,出错的概率越大,尤其是现场环境千差万别,和当初本地电脑测试环境很可能不一样,有很多特殊情况没有考虑到, ...

  10. 在C#中通过使用Newtonsoft.Json库来解析天地图地理编码(GeoCoder)服务接口返回的Json格式的数据,以及HttpWebRequest 设置不完全时服务器返回“远程服务器返回错误: (403) 已禁止”解决方法

    天地图地理编码(GeoCoder)服务接口返回的Json格式的数据,如下所示: http://api.tianditu.gov.cn/geocoder?ds={"keyWord": ...