【学习笔记】AGC043D Merge Triplets

不妨从必要条件入手,如果 a i > a i + 1 a_i>a_{i+1} ai>ai+1那么显然 i i i i + 1 i+1 i+1在同一块中,那么不妨做一个工作,按前缀 max ⁡ \max max将结果序列进行划分。

然后有一个神必的结论: c 1 ≥ c 2 c_1\ge c_2 c1c2(或者 c 2 + c 3 ≤ n c_2+c_3\le n c2+c3n),其中 c i c_i ci表示长度为 i i i的段的数目。证明考虑,将结果序列划分成 n n n个子序列,用 p i , j p_{i,j} pi,j表示第 i i i个子序列第 j j j个数的位置,那么 p i , 1 , p i , 2 , p i , 3 p_{i,1},p_{i,2},p_{i,3} pi,1,pi,2,pi,3递增并且对于 j = 2 , 3 j=2,3 j=2,3,满足 ( p i , j − 1 , p i , j ) (p_{i,j-1},p_{i,j}) (pi,j1,pi,j)之间的数均比 a p i , j a_{p_{i,j}} api,j小。显然划分的每一组的第一个数都是前缀最大值,因此构造是平凡的。那么方案数就是不同的划分数目。复杂度 O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h> #define pb push_back #define ll long long #define inf 0x3f3f3f3f using namespace std; const int N=6e3+5; int n,mod; int f[N][N]; void add(int &x,int y){ if((x+=y)>=mod)x-=mod; } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>mod;f[3*n][0]=1; for(int i=3*n;i>0;i--){ for(int j=0;j<=n;j++){ if(f[i][j]){ add(f[i-1][j],f[i][j]); if(i>=2)add(f[i-2][j+1],(ll)f[i][j]*(i-1)%mod); if(i>=3)add(f[i-3][j+1],(ll)f[i][j]*(i-1)%mod*(i-2)%mod); } } }int res(0); for(int i=0;i<=n;i++)add(res,f[0][i]); cout<<res; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530064.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示