1400D. Zigzags(dp转移emm)
发布日期:2021-06-30 10:20:42 浏览次数:3 分类:技术文章

本文共 2690 字,大约阅读时间需要 8 分钟。

二 分 明 显 超 时 , 因 为 枚 举 前 两 个 数 的 位 置 是 必 须 的 二分明显超时,因为枚举前两个数的位置是必须的 ,其实我没看出来

考 虑 直 接 枚 举 数 字 x 和 y , 找 到 x   y   x   y 的 四 元 组 个 数 考虑直接枚举数字x和y,找到x\ y\ x\ y的四元组个数 xy,x y x y

我们的目的是只枚举一次(x,y)就能在线性的时间完成计数

比 如 一 组 数 据 比如一组数据

1 2 1 1 2 1 2 2

如 何 找 到 1   2   1   2 的 四 元 组 个 数 ? 如何找到1\ 2\ 1\ 2的四元组个数? 1 2 1 2?

考 虑 d p , d p [ 1 ] 表 示 匹 配 到 1 的 个 数 , d p [ 2 ] 表 示 匹 配 到 1   2 的 个 数 考虑dp,dp[1]表示匹配到1的个数,dp[2]表示匹配到1\ 2的个数 dp,dp[1]1,dp[2]1 2

d p [ 3 ] 表 示 匹 配 到 1   2   1 的 个 数 , d p [ 4 ] 表 示 匹 配 到 1   2   1   2 的 个 数 dp[3]表示匹配到1\ 2\ 1的个数,dp[4]表示匹配到1\ 2\ 1\ 2的个数 dp[3]1 2 1,dp[4]1 2 1 2

那 么 当 遇 到 1 的 时 候 , 转 移 为 那么当遇到1的时候,转移为 1,

d p [ 1 ] + + ;   d p [ 3 ] + = d p [ 2 ] dp[1]++; \ dp[3]+=dp[2] dp[1]++; dp[3]+=dp[2]

当 遇 到 2 的 时 候 , 转 移 为 当遇到2的时候,转移为 2,

d p [ 2 ] + = d p [ 1 ] , d p [ 4 ] + = d p [ 3 ] dp[2]+=dp[1],dp[4]+=dp[3] dp[2]+=dp[1],dp[4]+=dp[3]

最 后 d p [ 4 ] 就 是 四 元 组 的 个 数 最后dp[4]就是四元组的个数 dp[4]

问 题 又 来 了 , 枚 举 x 和 y 后 , 如 何 把 x 元 素 和 y 元 素 从 a 数 组 中 剥 离 出 来 进 行 d p ? 问题又来了,枚举x和y后,如何把x元素和y元素从a数组中剥离出来进行dp? ,xy,xyadp?

简 单 , 记 录 一 些 x 元 素 出 现 第 一 次 的 位 置 , 第 二 次 的 位 置 . . . . . . 简单,记录一些x元素出现第一次的位置,第二次的位置...... ,x,......

那 么 通 过 这 个 数 组 , 我 们 可 以 快 速 找 到 只 包 含 x 和 y 的 序 列 那么通过这个数组,我们可以快速找到只包含x和y的序列 ,xy


至 于 时 间 复 杂 度 , 每 次 枚 举 x 和 y 的 复 杂 度 就 是 d p 包 含 x 和 y 的 序 列 至于时间复杂度,每次枚举x和y的复杂度就是dp包含x和y的序列 ,xydpxy

单 次 复 杂 度 在 g = ( x 数 量 + y 数 量 ) 单次复杂度在g=(x数量+y数量) g=(x+y)

意 会 一 下 , 枚 举 的 x 和 y 不 会 很 多 , 假 如 枚 举 的 x 和 y 很 多 说 明 g 很 小 意会一下,枚举的x和y不会很多,假如枚举的x和y很多说明g很小 ,xy,xyg

#include 
using namespace std;const int maxn=3009;#define int long longint t,n,a[maxn],b[maxn][maxn],id[maxn],f[6],vis[maxn];signed main(){ cin >> t; while( t-- ) { cin >> n; for(int i=1;i<=n;i++) { cin >> a[i]; vis[ a[i] ]++; ++id[ a[i] ]; b[ a[i] ][ id[a[i]] ]=i; } int ans=0; for(int i=1;i<=n;i++)//计算x x x x四元组的数量,这种情况单独计算方便一点 if( vis[i]>=4 ) { int x=vis[i]; ans+=x*(x-1)*(x-2)*(x-3)/4/3/2;//选4个即可 } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if( i==j ) continue; if( vis[i]==0||vis[j]==0 ) continue; int q=1,w=1; f[1]=f[2]=f[3]=f[4]=0; while( 1 ) { int index=1e9; if( q<=id[i] ) index=min(index,b[i][q] ); if( w<=id[j] ) index=min( index,b[j][w] ); if( index==b[i][q] ) q++; else w++; if( a[index]==i ) f[3]+=f[2],f[1]++; else f[4]+=f[3],f[2]+=f[1]; if( q>id[i]&&w>id[j] ) break; } ans+=f[4]; } cout << ans << '\n'; for(int i=1;i<=n;i++) { for(int j=1;j<=id[i];j++) b[i][j]=0; id[i]=0;vis[i]=0; } }}

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/108232108 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:1400E. Clear the Multiset(决策取优,或叫分治?)
下一篇:最大权闭合子图(最小割原理)

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月21日 10时22分24秒