首页 > 其他分享 >[dp 记录]agc024E Sequence Growing Hard

[dp 记录]agc024E Sequence Growing Hard

时间:2022-12-11 15:44:43浏览次数:54  
标签:val Sequence int Hard 插入 agc024E id dp mod

题意:

给定一个序列,每次往其中插入 \([1,k]\) 间的一数,要求字典序递增,求方案数。设插入 \(i\) 数的数列为 \(A_i\),存在一个 \(A_i\) 不同即两插入方案不同,否则即一致。

\(n,k \leq 300\)

添加一个数,该数后面第一个与它数字的数字小于它本身。注意到连续相同数可以插入到任意位置,不妨钦定插到最后面,则每次转移时 \(x_i > x_{i+1}\)。

这样仍然不好做。无论枚举填进去的数还是枚举填的位置都需要知道 \(n\) 个数的详细信息。

注意到操作序列能唯一确认方案,我们渴望找到什么能与操作序列双射。

看到操作序列,尤其转移与大小相关,可以考虑上树。

考虑怎样计数操作,不会做。试想更简单的问题:对于一个确定的序列,怎样刻画“插入”操作并对其计数?根据性质,一个数会插入在另一个数前。因此,可以考虑向位置靠后的数连边。这样,每个位置都有一个出边,只有虚点没有出边。所以这是一棵树,树上每个节点的父亲的权值都严格小于它。

—— https://www.luogu.com.cn/blog/Yansuan-HCl/solution-at-agc024-e

这样还是不易于统计,再做一步转化,把每个字符的位置用它被插入的时间表示。那么我们需要做的即是对每次操作,选择之前的一次操作表示这次插在之前插的位置前面。特别地,选择 \(0\) 操作表示这次插在最后面。

——https://www.luogu.com.cn/blog/0123456-3456789/solution-at3962

一次插入操作可以用它插入时在它后面的数刻画。所以连边,自然构成一棵树。

定义一个节点的权值为二元组 \((val, id)\),每次操作新建点挂到它后面的点下面,\(id\) 为插入时间,\(val\) 为权值。则 \(\forall v\) 为 \(u\) 儿子,\(val_v > val_u,id_v > id_u\)。容易验证这样的树与操作序列双射。这是漂亮的有传递性的偏序关系,无后效性的子结构,可以进行 dp 了。

记录三维(大小也是应该关心的)还是多了些。发现每次转移相当于加一棵子树进来,钦定那是 \(id\) 最小或 \(val\) 最小就可以不用记录其中一者转移了。

\(id\) 是排列,关于排列的平移是唯一的,所以钦定 \(id\) 最小是好做的。

设 \(dp_{v,x}\) 表示根节点 \(val=v,siz=x\) 的树的方案数。转移:

\[dp_{v,x} = \sum_{i=v+1}^{k} \sum_{y=1}^{x-1} dp_{i,y}dp_{v,x-y}\binom{x-2}{y-1} \]

后面的组合数是因为两边的 \(val\) 的相对顺序没有限制,除了两个根以外的相对顺序都可以随意选择。

把 \(i\) 这一维后缀和滚掉即可做到 \(O(n^3)\)。

#include <cstdio>
using namespace std;
const int M = 305;
int mod;
int add(int a, int b) {a += b; return a > mod ? a-mod : a;}
int mins(int a, int b) {a -= b; return a < 0 ? a+mod : a;}
void addn(int &x, int y) {x += y; if(x > mod) x -= mod;}
int n, dp[M][M], k, C[M][M], s[M][M];
int main(){
    scanf("%d %d %d", &n, &k, &mod);
    C[0][0] = 1;
    for(int i = 1; i <= n; i++) {
        C[i][0] = 1;
        for(int j = 1; j <= i; j++) 
            C[i][j] = add(C[i-1][j-1], C[i-1][j]);
        printf("\n");
    }
    for(int i = 0; i <= k; i++) dp[i][1] = 1, s[i][1] = k-i+1;
    for(int x = 2; x <= n+1; x++) {
        for(int v = k; v >= 0; v--) {
            for(int y = 1; y < x; y++) 
                addn(dp[v][x], 1ll * C[x-2][y-1] * s[v+1][y] % mod * dp[v][x-y] % mod);
            s[v][x] = add(s[v+1][x], dp[v][x]);
        }
    }
    printf("%d\n", dp[0][n+1]);
}

标签:val,Sequence,int,Hard,插入,agc024E,id,dp,mod
From: https://www.cnblogs.com/purplevine/p/16973754.html

相关文章

  • vs插件git-extension提示长度不能小于0,输出窗口提示fatal: unexpected sequence from
    废话不多说,正解来自于VisualStudio的Git不能使用,提示长度不能小于0?-知乎(zhihu.com)的最后一条,ip-guard限制了VS的devenv.exe应用。本来很早就怀疑是ip-guard的原因,但......
  • ShardingCore兼容Code-First数据库迁移 让update-database能更新分表
    参考文章.Net下极限生产力之分表分库全自动化MigrationsCode-First背景在我上一篇博客ABPEFCORE7集成ShardingCore实现分表写完之后,我发现我还有一个没解决的问......
  • [Typescript] 130. Hard - Replace Union
    Givenan unionoftypes and arrayoftypepairs toreplace([[string,number],[Date,null]]),returnanewunionreplacedwiththe typepairs. /*____......
  • rabbitmq-sharding插件使用
    RabbitMQ是非常流行的消息中间件,大家都知道通过集群能够增大它的吞吐量,那么针对单个队列,集群能增大他的吞吐量吗?如果不能,我们要怎么做呢?南山远眺问题RabbitMQ是非常流行的消......
  • VIP06-ShardingSphere5.x新版本特性
    一、整体理解新版本二、5.X部分新特性1、DistSQL2、可插拔内核3、数据迁移三、全部内容总结 一、整体理解新版本​ShardingSphere在2021年十月份推出了5.0......
  • [Typescript] 129. Hard - Capitalize Nest Object Keys
    Capitalizethekeyoftheobject,andifthevalueisanarray,iteratethroughtheobjectsinthearray. /*_____________YourCodeHere_____________*/......
  • hdu4632 Palindrome subsequence--区间dp
    原题链接:​​http://acm.hdu.edu.cn/showproblem.php?pid=4632​​题意:求一个字符串所有子序列是回文的个数,注意子序列是这样的情况:原串abcde,子串abd。注意与子串含义不同。......
  • hardware infomation query
    1.CPU查看物理CPU个数、核数、逻辑CPU个数#总核数=物理CPU个数X每颗物理CPU的核数#总逻辑CPU数=物理CPU个数X每颗物理CPU的核数X超线程数#查看物理CPU......
  • LeetCode: 300. Longest Increasing Subsequence
    LeetCode:300.LongestIncreasingSubsequence题目描述Givenanunsortedarrayofintegers,findthelengthoflongestincreasingsubsequence.Example:Input:[10,......
  • [Typescript] 127. Hard - Assign
    Youhaveatargetobjectandasourcearrayofobjects.Youneedtocopypropertyfromsourcetotarget,ifithasthesamepropertyasthesource,youshould......