当前位置: 首页 > news >正文

球球的排列

题目传送门

计数DP,好像特别经典,有两种做法,我只会 O ( n 3 ) O(n^3) O(n3),有 O ( n 2 ) O(n^2) O(n2)

解法

首先, 若 x y = p 2 且 x z = q 2 , 则 y z = ( p q x ) 2 若xy=p^2且xz=q^2,则yz=(\frac{pq}{x} )^2 xy=p2xz=q2,yz=(xpq)2 所以题目中给出的关系具有传递性,故先预处理,不可相邻的球分在一个组
为了方便,下面叫同一组的球为同色
伪代码如下:

bool check(ll x){ll tmp=sqrt(x);return (tmp*tmp==x);
}for(int i=1;i<=n;i++) {a[i]=read(),b[i]=i;for(int j=1;j<i;j++) {if(check(1ll*a[i]*a[j])) {b[i]=j;break;}}
}

接下来,

设计状态

首先我们无脑枚举一维 i i i表示前 i i i个球,注意同色的球排序后的序列是连续的
观察题目的限制相当于同色的球不能相邻,设计后两维要考虑好同色相邻
f i , j , . k : 前 i 个球,共有 j + k 对相邻的球同色,其中 j 对跟第 i 个球异色, k 对同色 f_{i,j,.k}:前i个球,共有j+k对相邻的球同色,其中j对跟第i个球异色,k对同色 fi,j,.k:i个球,共有j+k对相邻的球同色,其中j对跟第i个球异色,k对同色
那么最后的答案 a n s = f n , 0 , 0 ans=f_{n,0,0} ans=fn,0,0
设计出了状态其实就成功了一半,但这道题的转移也很毒瘤,客官且看

状态转移

考虑 f i f_i fi f i − 1 f_{i-1} fi1的关系, f i f_i fi的状态都是由 i − 1 i-1 i1个球的 i i i个空隙插入一个球而来的
那么第 i i i个球与第 i − 1 i-1 i1个球有两种关系:a.同色;b.异色
i i i个球插入的位置也有两种可能:c.插入两个同色球之间;d.插入两个异色球之间
所以对6种可能分别考虑转移:

1. a与c

发现,此时前 i − 1 i-1 i1个球已有与 i i i同色的,那么明显第 i i i个球放在与其同色的球旁边转移不同,设排列中已有 c n t cnt cnt个球与 i i i同色,此时有:
f i , j , k = f i − 1 , j , k − 1 ∗ ( c n t ∗ 2 − ( k − 1 ) ) f_{i,j,k}=f_{i-1,j,k-1}*(cnt*2-(k-1)) fi,j,k=fi1,j,k1cnt2(k1)
然后第 i i i个球插入的位置是与自己异色的球间,让 j j j减少了1,此时有:
f i , j , k = f i − 1 , j + 1 , k ∗ ( j + 1 ) f_{i,j,k}=f_{i-1,j+1,k}*(j+1) fi,j,k=fi1,j+1,k(j+1)

2.a与d

减去前两种情况,还剩 i − c n t ∗ 2 + k − j i-cnt*2+k-j icnt2+kj种情况, j , k j,k j,k不变,此时有:
f i , j , k = f i − 1 , j , k ∗ ( i − c n t ∗ 2 + k − j ) f_{i,j,k}=f_{i-1,j,k}*(i-cnt*2+k-j) fi,j,k=fi1,j,k(icnt2+kj)

3.b与c

可知第 i i i个球的颜色是首次出现,故 k k k=0,让 ( j + k ) (j+k) (j+k)减少了1,所以要枚举 j ‘ j‘ j k ’ k’ k,有:
f i , j , 0 = ∑ j ′ + k ′ = j + 1 f i , j ′ , k ′ ∗ ( j + 1 ) f_{i,j,0}=\sum_{j'+k'=j+1} f_{i,j',k'} *(j+1) fi,j,0=j+k=j+1fi,j,k(j+1)

4.b与d

j , k j,k j,k不产生影响,枚举即可,此时有:
f i , j , 0 = ∑ j ′ + k ′ = j f i , j ′ , k ′ ∗ ( i − j ) f_{i,j,0}=\sum_{j'+k'=j} f_{i,j',k'}*(i-j) fi,j,0=j+k=jfi,j,k(ij)

代码实现倒是简单,放一下

code:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 3e2 + 5,mod=1e9+7;
int n,cnt;
int f[2][N][N],a[N],b[N];
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;
}
bool check(ll x){ll tmp=sqrt(x);return (tmp*tmp==x);
}
int main() {n=read();for(int i=1;i<=n;i++) {a[i]=read(),b[i]=i;for(int j=1;j<i;j++) {if(check(1ll*a[i]*a[j])) {b[i]=j;break;}}}sort(b+1,b+1+n);f[0][0][0]=1;for(int i=1;i<=n;i++,cnt++) {int now=i&1,pre=now^1;memset(f[now],0,sizeof f[now]);if(b[i]==b[i-1]){for(int j=0;j<i;j++) {for(int k=0;k<=cnt;k++){if(k) f[now][j][k]=(1ll*f[now][j][k]+1ll*f[pre][j][k-1]*(cnt*2-(k-1)))%mod;f[now][j][k]=(1ll*f[now][j][k]+1ll*f[pre][j+1][k]*(j+1))%mod;f[now][j][k]=(1ll*f[now][j][k]+1ll*f[pre][j][k]*(i-cnt*2+k-j))%mod;}}}else {cnt=0;for(int j=0;j<i;j++){for(int k=0;k<=j+1;k++){if(k<=j) f[now][j][0]=(1ll*f[now][j][0]+1ll*f[pre][k][j-k]*(i-j))%mod;f[now][j][0]=(1ll*f[now][j][0]+1ll*f[pre][k][(j+1)-k]*(j+1))%mod;}}}}printf("%d\n",f[n&1][0][0]);
}

TXL

http://www.lryc.cn/news/153374.html

相关文章:

  • 1783_CMD启动MATLAB同时执行一个脚本
  • C语言中内存分配的几种方式
  • 组相联cache如何快速实现cache line eviction并使用PMU events验证
  • 【Stable Diffusion安装】支持python3.11 window版
  • Anycloud37D平台移植wirelesstools
  • 海康机器人工业相机 Win10+Qt+Cmake 开发环境搭建
  • 使用MDK5的一些偏僻使用方法和谋个功能的作用
  • 【实战】十一、看板页面及任务组页面开发(六) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十八)
  • 在 Amazon 搭建无代码可视化的数据分析和建模平台
  • Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)
  • elasticSearch+kibana+logstash+filebeat集群改成https认证
  • GPT带我学-设计模式-迭代器模式
  • 数学建模--层次分析法(AHP)的Python实现
  • 机器学习笔记之最优化理论与方法(三)凸集的简单认识(下)
  • Apipost:API文档、调试、Mock与测试的一体化协作平台
  • Homebrew下载安装及使用教程
  • 【Codeforces】CF193D Two Segments
  • 内存管理概述
  • Spring的重试机制-SpringRetry
  • 水稻叶病害数据集(目标检测,yolo使用)
  • 鸿蒙系列-如何使用好 ArkUI 的 @Reusable?
  • 展锐平台音频框架
  • webpack loader和plugins的区别
  • 适配器模式:接口的平滑过渡
  • vscode搭建springboot开发环境
  • SpringMVC-学习笔记
  • 【STM32】学习笔记(TIM定时器)
  • Jdk8 动态编译 Java 源码为 Class 文件(三)
  • Shell自动化日志维护脚本
  • 设计模式入门笔记