Atcoder ABC387F Count Arrays 题解 [ 绿 ] [ 基环树 ] [ 树形 dp ] [ 前缀和优化 ]
Count Arrays:一眼秒的计数题。
思路
显然,把小于等于的条件化为大的向小的连单向边,每个数的入度都是
那么考虑这个环上能填什么数。因为所有数都小于等于他后面的数,所以所有数都只能相等。这就启发我们在基环树上缩点之后再进行计数。
那么当缩完点计数时如何计算呢?有个很简单的 dp,定义
直接转移是
答案计算时将所有基环树的答案乘起来即可。
代码
#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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战