一个成熟的表单

表单表单,你已经长大了,你要学会:

  • 动态渲染
  • 支持单列、双列、多列
  • 支持调整布局
  • 支持表单验证
  • 支持调整排列(显示)顺序
  • 依据组件值显示需要的组件
  • 支持 item 扩展组件
  • 可以自动创建 model

这个表单控件是基于 element-plus 的 el-form 做的二次封装,所以首先感谢 element-plus 提供了这么强大的UI库,以前用 jQuery 做过类似的,但是非常麻烦,既不好看,可维护性、扩展性也差,好多想法都实现不了(技术有限)。

现在好了,站在巨人的肩膀上,实现自己的想法了。

实现动态渲染

把表单需要的属性,统统放入json里面,然后用require(方便) 或者aioxs(可以热更新)加载进来,这样就可以实现动态渲染了。

比如要实现公司信息的添加、修改,那么只需要加载公司信息需要的json即可。

想要实现员工信息的添加、修改,那么只需要加载员工信息需要的json。

总之,加载需要的json即可,不需要再一遍一遍的手撸代码了。

那么这个神奇的 json 是啥样子的呢?文件有点长,直接看截图,更清晰一些。

另外还有几个附带功能:

  • 支持单行下的合并。

    在单行的情况下,一些短的控件会比较占空间,我们可以把多个小的合并到一行。

  • 支持多行下的扩展。

    多行的情况下,一些长的控件需要占更多的空间,我们可以设置它多占几个格子。

  • 自动创建表单需要的 model。

    不需要手动写 model了。

实现多行多列的表单

再次感谢 el-form,真的很强大,不仅好看,还提供了验证功能,还有很多其他的功能。

只是好像只能横着排,或者竖着排。那么能不能多行多列呢?似乎没有直接提供。

我们知道 el-row、el-col 可以实现多行多列的功能,那么能不能结合一下呢?官网也不直说,害的我各种找,还好找到了。(好吧,其实折腾了一阵着的table)

二者结合一下就可以了,这里有个小技巧,el-row 只需要一个就可以,el-col 可以有多个,这样一行排满后,会自动排到下一行。

    <el-form
ref="form"
:inline="false"
class="demo-form-inline"
:model="formModel"
label-suffix=":"
label-width="130px"
size="mini"
>
<el-row>
<!--不循环row,直接循环col,放不下会自动往下换行。-->
<el-col
v-for="(ctrId, index) in formColSort"
:key="'form_'+index"
:span="formColSpan[ctrId]"
>
<el-form-item :label="getCtrMeta(ctrId).label">
<!--表单item组件,采用动态组件的方式-->
<component
:is="ctlList[getCtrMeta(ctrId).controlType]"
v-model="formModel[getCtrMeta(ctrId).colName]"
:meta="getCtrMeta(ctrId)"
@myChange="mySubmit">
</component>
</el-form-item>
</el-col>
</el-row>
</el-form>
  • formColSort

    存放组件ID的数组,决定了显示哪些组件以及显示的先后顺序。

  • v-for

    遍历 formColSort 得到组件ID,然后获取ID对应的span(确定占位)以及组件需要的meta。

  • formColSpan

    存放组件占位的数组。依据el-col的span的24格设定。

  • getCtrMeta(ctrId)

    根据组件ID获取组件的meta。

    为啥要写个函数呢?因为model的属性不允许中括号套娃,所以只好写个函数。

    为啥不用计算属性呢?计算属性好像不能传递参数。

  • component :is="xxx"

    Vue提供的动态组件,用这个可以方便加载不同类型的子组件。

  • ctlList

    组件字典,把组件类型变成对应的组件标签。

这样一个v-for搞定了很多事情,比如单列、多列,组件的排序问题,组件的占位问题,还有依据用户的选择显示不同的组件的问题,其实就是修改一下 formColSort 里的组件ID的构成和顺序。

自动创建 model

我比较懒,手撸 model 是不是有点麻烦?如果能够自动获得该多好,于是我写了这个函数。

  // 根据表单元素meta,创建 v-model
const createModel = () => {
// 依据meta,创建module
for (const key in formItemMeta) {
const m = formItemMeta[key]
// 根据控件类型设置属性值
switch (m.controlType) {
case 100: // 文本类
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 130:
case 131:
formModel[m.colName] = ''
break
case 110: // 日期
case 111: // 日期时间
case 112: // 年月
case 114: // 年
case 113: // 年周
formModel[m.colName] = null
break
case 115: // 任意时间
formModel[m.colName] = '00:00:00'
break
case 116: // 选择时间
formModel[m.colName] = '00:00'
break
case 120: // 数字
case 121:
formModel[m.colName] = 0
break
case 150: // 勾选
case 151: // 开关
formModel[m.colName] = false
break
case 153: // 单选组
case 160: // 下拉单选
case 162: // 下拉联动
formModel[m.colName] = null
break
case 152: // 多选组
case 161: // 下拉多选
formModel[m.colName] = []
break
}
// 看看有没有设置默认值
if (typeof m.defaultValue !== 'undefined') {
switch (m.defaultValue) {
case '':
break
case '{}':
formModel[m.colName] = {}
break
case '[]':
formModel[m.colName] = []
break
case 'date':
formModel[m.colName] = new Date()
break
default:
formModel[m.colName] = m.defaultValue
break
}
}
}
// 同步父组件的v-model
context.emit('update:modelValue', formModel)
return formModel
}

可以根据类型和默认值,设置 model 的属性,这样就方便多了。

创建用户选择的 model

就是用户选了某个选项,表单的组件响应变化后的model。

在我的计划里面是需要一个这样的简单的model,所以我又写了一个函数

  // 依据用户选项,创建对应的 model
const createPartModel = (array) => {
// 先删除属性
for (const key in formPartModel) {
delete formPartModel[key]
}
// 建立新属性
for (let i = 0; i < array.length; i++) {
const colName = formItemMeta[array[i]].colName
formPartModel[colName] = formModel[colName]
}
}

这样就可以得到一个简洁的 model 了。

多列的表单

这个是最复杂的,分为两种情况:单列的挤一挤、多列的抢位置。

单列

单列的表单有一个特点,一行比较宽松,那么有时候就需要两个组件在一行里显示,其他的还是一行一个组件,那么要如何调整呢?

这里做一个设定:

  • 一个组件一行的,记做1
  • 两个组件挤一行的,记做-2
  • 三个组件挤一行的,记做-3

    以此类推,理论上最多支持 -24,当然实际上似乎没有这么宽的显示器。

这样记录之后,我们就可以判断,≥1的记做span=24,负数的,用24去除,得到的就是span的数字。当然记得取整数。

为啥用负数做标记呢?就是为了区分开多列的调整。

多列

调多了之后发现一个问题,看起来和单列调整后似乎一样的。

多列的表单有一个特点,一个格子比较小,有些组件太长放不下,这个时候这个组件就要抢后面的格子来用。

那么我们还是做一个设定:

  • 一个组件占一格的,还是记做1
  • 一个组件占两格的,记做2
  • 一个组件占三格的,记做3

    以此类推。

这样记录之后,我们可以判断,≤1的,记做 24 / 列数,大于1的记做 24/ 列数 * n。

这样就可以了,可以兼容单列的设置,不用因为单列变多列而调整设置。

只是有个小麻烦,占得格子太多的话,就会提取挤到下一行,而本行会出现“空缺”。

这个暂时靠人工调整吧。

毕竟哪个字段在前面,还是需要人工设置的。

一顿分析猛如虎,一看代码没几行。

  // 根据配置里面的colCount,设置 formColSpan
const setFormColSpan = () => {
const formColCount = formMeta.formColCount // 列数
const moreColSpan = 24 / formColCount // 一个格子占多少份 if (formColCount === 1) {
// 一列的情况
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
formColSpan[m.controlId] = moreColSpan
} else {
if (m.colCount >= 1) {
// 单列,多占的也只有24格
formColSpan[m.controlId] = moreColSpan
} else if (m.colCount < 0) {
// 挤一挤的情况, 24 除以 占的份数
formColSpan[m.controlId] = moreColSpan / (0 - m.colCount)
}
}
}
} else {
// 多列的情况
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
formColSpan[m.controlId] = moreColSpan
} else {
if (m.colCount < 0 || m.colCount === 1) {
// 多列,挤一挤的占一份
formColSpan[m.controlId] = moreColSpan
} else if (m.colCount > 1) {
// 多列,占的格子数 * 份数
formColSpan[m.controlId] = moreColSpan * m.colCount
}
}
}
}
}

最后看看效果,可以动态设置列数:

【视频一】

https://www.zhihu.com/zvideo/1347091197660405760

依据用户的选择,显示对应的组件

这个也是一个急需的功能,否则的话,动态渲染的表单控件适应性就会受到限制。

其实想想也不难,就是改一下 formColSort 里面的组件ID就好了。

我们设置一个watch来监听组件值的变化,然后把需要的组件ID设置给 formColSort 就可以了。

  // 监听组件值的变化,调整组件的显示以及显示顺序
if (typeof formMeta.formColShow !== 'undefined') {
for (const key in formMeta.formColShow) {
const ctl = formMeta.formColShow[key]
const colName = formItemMeta[key].colName
watch(() => formModel[colName], (v1, v2) => {
if (typeof ctl[v1] === 'undefined') {
// 没有设定,显示默认组件
setFormColSort()
} else {
// 按照设定显示组件
setFormColSort(ctl[v1])
// 设置部分的 model
createPartModel(ctl[v1])
}
})
}
}

因为需要监听的组件可能不只一个,所以做了个循环,这样就可以监听所有需要的组件了。

看看效果

【视频二】

https://www.zhihu.com/zvideo/1347099700483457024

完整代码

上面的代码比较凌乱,这里整体介绍一下。

  • el-form-manage.js

    表单组件的管理类,单独拿出来,这样就可以支持其他UI库了,比如antdv
import { reactive, watch } from 'vue'

/**
* 表单的管理类
* * 创建v-model
* * 调整列数
* * 合并
*/
const formManage = (props, context) => {
// 定义 完整的 v-model
const formModel = reactive({})
// 定义局部的 model
const formPartModel = reactive({}) // 确定一个组件占用几个格子
const formColSpan = reactive({})
// 定义排序依据
const formColSort = reactive([])
// 获取表单meta
const formMeta = props.meta
console.log('formMeta', formMeta)
// 表单元素meta
const formItemMeta = formMeta.itemMeta
// 表单验证meta,备用
// const formRuleMeta = formMeta.ruleMeta // 根据表单元素meta,创建 v-model
const createModel = () => {
// 依据meta,创建module
for (const key in formItemMeta) {
const m = formItemMeta[key]
// 根据控件类型设置属性值
switch (m.controlType) {
case 100: // 文本类
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 130:
case 131:
formModel[m.colName] = ''
break
case 110: // 日期
case 111: // 日期时间
case 112: // 年月
case 114: // 年
case 113: // 年周
formModel[m.colName] = null
break
case 115: // 任意时间
formModel[m.colName] = '00:00:00'
break
case 116: // 选择时间
formModel[m.colName] = '00:00'
break
case 120: // 数字
case 121:
formModel[m.colName] = 0
break
case 150: // 勾选
case 151: // 开关
formModel[m.colName] = false
break
case 153: // 单选组
case 160: // 下拉单选
case 162: // 下拉联动
formModel[m.colName] = null
break
case 152: // 多选组
case 161: // 下拉多选
formModel[m.colName] = []
break
}
// 看看有没有设置默认值
if (typeof m.defaultValue !== 'undefined') {
switch (m.defaultValue) {
case '':
break
case '{}':
formModel[m.colName] = {}
break
case '[]':
formModel[m.colName] = []
break
case 'date':
formModel[m.colName] = new Date()
break
default:
formModel[m.colName] = m.defaultValue
break
}
}
}
// 同步父组件的v-model
context.emit('update:modelValue', formModel)
return formModel
}
// 先运行一次
createModel() // 向父组件提交 model
const mySubmit = (val, controlId, colName) => {
context.emit('update:modelValue', formModel)
// 同步到部分model
if (typeof formPartModel[colName] !== 'undefined') {
formPartModel[colName] = formModel[colName]
}
context.emit('update:partModel', formPartModel)
} // 依据用户选项,创建对应的 model
const createPartModel = (array) => {
// 先删除属性
for (const key in formPartModel) {
delete formPartModel[key]
}
// 建立新属性
for (let i = 0; i < array.length; i++) {
const colName = formItemMeta[array[i]].colName
formPartModel[colName] = formModel[colName]
}
} // 根据配置里面的colCount,设置 formColSpan
const setFormColSpan = () => {
const formColCount = formMeta.formColCount // 列数
const moreColSpan = 24 / formColCount // 一个格子占多少份 if (formColCount === 1) {
// 一列的情况
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
formColSpan[m.controlId] = moreColSpan
} else {
if (m.colCount >= 1) {
// 单列,多占的也只有24格
formColSpan[m.controlId] = moreColSpan
} else if (m.colCount < 0) {
// 挤一挤的情况, 24 除以 占的份数
formColSpan[m.controlId] = moreColSpan / (0 - m.colCount)
}
}
}
} else {
// 多列的情况
for (const key in formItemMeta) {
const m = formItemMeta[key]
if (typeof m.colCount === 'undefined') {
formColSpan[m.controlId] = moreColSpan
} else {
if (m.colCount < 0 || m.colCount === 1) {
// 多列,挤一挤的占一份
formColSpan[m.controlId] = moreColSpan
} else if (m.colCount > 1) {
// 多列,占的格子数 * 份数
formColSpan[m.controlId] = moreColSpan * m.colCount
}
}
}
}
}
// 先运行一次
setFormColSpan() // 设置组件的显示顺序
const setFormColSort = (array = formMeta.colOrder) => {
formColSort.length = 0
formColSort.push(...array)
}
// 先运行一下
setFormColSort() // 监听组件值的变化,调整组件的显示以及显示顺序
if (typeof formMeta.formColShow !== 'undefined') {
for (const key in formMeta.formColShow) {
const ctl = formMeta.formColShow[key]
const colName = formItemMeta[key].colName
watch(() => formModel[colName], (v1, v2) => {
if (typeof ctl[v1] === 'undefined') {
// 没有设定,显示默认组件
setFormColSort()
} else {
// 按照设定显示组件
setFormColSort(ctl[v1])
// 设置部分的 model
createPartModel(ctl[v1])
}
})
}
} return {
// 对象
formModel, // v-model createModel()
formPartModel, // 用户选择的组件的 model
formColSpan, // 确定组件占位
formColSort, // 确定组件排序
// 函数
createModel, // 创建 v-model
setFormColSpan, // 设置组件占位
setFormColSort, // 设置组件排序
mySubmit // 提交
}
} export default formManage
  • el-form-map.js

    动态组件需要的字典
import { defineAsyncComponent } from 'vue'

/**
* 组件里面注册控件用
* * 文本
* ** eltext 单行文本、电话、邮件、搜索
* ** elarea 多行文本
* ** elurl
* * 数字
* ** elnumber 数字
* ** elrange 滑块
* * 日期
* ** eldate 日期、年月、年周、年
* ** eltime 时间
* * 选择
* ** elcheckbox 勾选
* ** elswitch 开关
* ** elcheckboxs 多选组
* ** elradios 单选组
* ** elselect 下拉选择
*/
const formItemList = {
// 文本类 defineComponent
eltext: defineAsyncComponent(() => import('./t-text.vue')),
elarea: defineAsyncComponent(() => import('./t-area.vue')),
elurl: defineAsyncComponent(() => import('./t-url.vue')),
// 数字
elnumber: defineAsyncComponent(() => import('./n-number.vue')),
elrange: defineAsyncComponent(() => import('./n-range.vue')),
// 日期、时间
eldate: defineAsyncComponent(() => import('./d-date.vue')),
eltime: defineAsyncComponent(() => import('./d-time.vue')),
// 选择、开关
elcheckbox: defineAsyncComponent(() => import('./s-checkbox.vue')),
elswitch: defineAsyncComponent(() => import('./s-switch.vue')),
elcheckboxs: defineAsyncComponent(() => import('./s-checkboxs.vue')),
elradios: defineAsyncComponent(() => import('./s-radios.vue')),
elselect: defineAsyncComponent(() => import('./s-select.vue')),
elselwrite: defineAsyncComponent(() => import('./s-selwrite.vue'))
} /**
* 动态组件的字典,便于v-for循环里面设置控件
*/
const formItemListKey = {
// 文本类
100: formItemList.elarea, // 多行文本
101: formItemList.eltext, // 单行文本
102: formItemList.eltext, // 密码
103: formItemList.eltext, // 电话
104: formItemList.eltext, // 邮件
105: formItemList.elurl, // url
106: formItemList.eltext, // 搜索
// 数字
120: formItemList.elnumber, // 数组
121: formItemList.elrange, // 滑块
// 日期、时间
110: formItemList.eldate, // 日期
111: formItemList.eldate, // 日期 + 时间
112: formItemList.eldate, // 年月
113: formItemList.eldate, // 年周
114: formItemList.eldate, // 年
115: formItemList.eltime, // 任意时间
116: formItemList.eltime, // 选择固定时间
// 选择、开关
150: formItemList.elcheckbox, // 勾选
151: formItemList.elswitch, // 开关
152: formItemList.elcheckboxs, // 多选组
153: formItemList.elradios, // 单选组
160: formItemList.elselect, // 下拉
161: formItemList.elselwrite, // 下拉多选
162: formItemList.elselect // 下拉联动 } export default {
formItemList,
formItemListKey
}
  • el-form-div.vue

    表单控件的代码

    模板
  <div >
<el-form
ref="form"
:inline="false"
class="demo-form-inline"
:model="formModel"
label-suffix=":"
label-width="130px"
size="mini"
>
<el-row>
<!--不循环row,直接循环col,放不下会自动往下换行。-->
<el-col
v-for="(ctrId, index) in formColSort"
:key="'form_'+index"
:span="formColSpan[ctrId]"
>
<el-form-item :label="getCtrMeta(ctrId).label">
<!--表单item组件,采用动态组件的方式-->
<component
:is="ctlList[getCtrMeta(ctrId).controlType]"
v-model="formModel[getCtrMeta(ctrId).colName]"
:meta="getCtrMeta(ctrId)"
@myChange="mySubmit">
</component>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>

js

import { watch } from 'vue'
import elFormConfig from '@/components/nf-el-form/el-form-map.js'
import formManage from '@/components/nf-el-form/el-form-manage.js' export default {
name: 'el-form-div',
components: {
...elFormConfig.formItemList
},
props: {
modelValue: Object,
partModel: Object,
meta: Object
},
setup (props, context) {
// 控件字典
const ctlList = elFormConfig.formItemListKey // 表单管理类
const {
formModel, // 依据meta,创建 Model
formColSpan, // 依据meta,创建 span
formColSort,
setFormColSpan,
setFormColSort, // 设置组件排序
mySubmit
} = formManage(props, context) // 监听列数的变化
watch(() => props.meta.formColCount, (v1, v2) => {
setFormColSpan()
})
// 监听reload
watch(() => props.meta.reload, (v1, v2) => {
setFormColSpan()
setFormColSort()
}) // 监听组件值的变化,
// 依据ID获取组件的meta,因为model不支持【】嵌套
const getCtrMeta = (id) => {
return props.meta.itemMeta[id] || {}
} return {
formModel,
formColSpan,
formColSort,
ctlList,
getCtrMeta,
mySubmit
}
}
}

这里就简单多了,因为实现具体功能的js代码都分离出去了。要么做成子组件,要么组成独立的js文件。

这里主要就是负责重新渲染表单组件。

表单验证

这个使用 el-form 提供的验证功能。

目前暂时还没有归纳好 el-form 的验证,因为需要把这个验证用的数据写入到json里面,然后读取出来设置好即可。

所以肯定没难度,只是需要点时间。

支持 扩展组件

自带的组件肯定是不够的,因为用户的需求总是千变万化的,那么新组件如何加入到表单控件里面呢?可以按照接口定义封装成符合要求的组件,然后做一个map字典,就可以设置进去了。

因为接口统一,所以可以适应表单控件的调用。

简单的方法是,直接修改两个js文件。

如果不方便修改的话,也可以通过属性传递进来。目前暂时还没有想好细节,不过似乎不是太难。

源码

https://github.com/naturefwvue/nf-vue-element

Vue3组件(九)Vue + element-Plus + json = 动态渲染的表单控件的更多相关文章

  1. 基于 el-form 封装一个依赖 json 动态渲染的表单控件

    nf-form 表单控件的功能 基于 el-form 封装了一个表单控件,包括表单的子控件. 既然要封装,那么就要完善一些,把能想到的功能都要实现出来,不想留遗憾. 毕竟UI库提供的功能都很强大了,不 ...

  2. Vue.js学习笔记 第七篇 表单控件绑定

    本篇主要说明表单控件的数据绑定,这次没有新的知识点 文本框 1.普通文本框 <div id="app-1"> <p><input v-model=&q ...

  3. 如何给动态添加的form表单控件添加表单验证

    最近使用jQuery Validate做表单验证很方便,api地址为http://www.runoob.com/jquery/jquery-plugin-validate.html 但是在使用的时候也 ...

  4. vue.js基础知识篇(3):计算属性、表单控件绑定

    第四章:计算属性 为了避免过多的逻辑造成模板的臃肿不堪,可使用计算属性来简化逻辑. 1.什么是计算属性 <!DOCTYPE html><html lang="en" ...

  5. Vue.js-----轻量高效的MVVM框架(七、表单控件绑定)

    话不多说,先上完整代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  6. Vue#表单控件绑定

    使用v-model 在表单控件上实现数据双向绑定. 单选:https://jsfiddle.net/miloer/bs49p0fx/ <input type="checkbox&quo ...

  7. Vue.js学习 Item9 – 表单控件绑定

    基础用法 可以用 v-model 指令在表单控件元素上创建双向数据绑定.根据控件类型它自动选取正确的方法更新元素.尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据,以及特别处理一些 ...

  8. Vue表单控件绑定

    前面的话 本文将详细介绍Vue表单控件绑定 基础用法 可以用 v-model 指令在表单控件元素上创建双向数据绑定.它会根据控件类型自动选取正确的方法来更新元素.v-model本质上不过是语法糖,它负 ...

  9. Vue.js学习笔记——表单控件实践

    最近项目中使用了vue替代繁琐的jquery处理dom的数据更新,个人非常喜欢,所以就上官网小小地实践了一把. 以下为表单控件的实践,代码敬上,直接新建html文件,粘贴复制即可看到效果~ <! ...

随机推荐

  1. Oracle数据库之——分组查询,子查询及添加,更新,删除

    分组查询 写的顺序: select...from...where... group by...having...order by... 执行顺序: from...where...group by... ...

  2. Spark运行程序异常信息: org.apache.spark.SparkException: Task not serializable 解决办法

    错误信息: 17/05/20 18:51:39 ERROR JobScheduler: Error running job streaming job 1495277499000 ms.0 org.a ...

  3. nohup和&后台运行,进程查看及终止

    文章目录 一.nohup 1.1用途:不挂断地运行命令. 1.2语法:nohup Command [ Arg - ] [ & ] 1.3退出状态:该命令返回下列出口值: 二.& 2.1 ...

  4. linux常用命令(shell脚本常用命令)(grep、cut、sort、uniq、seq、tr、basename、dirname)

    本章命令: 1 2 3 4 5 6 grep cut sort uniq seq tr 1.grep 作用:过滤文本内容 选项 描述 -E :--extended--regexp 模式是扩展正则表达式 ...

  5. SpringBoot - 实现文件上传2(多文件上传、常用上传参数配置)

    在前文中我介绍了 Spring Boot 项目如何实现单文件上传,而多文件上传逻辑和单文件上传基本一致,下面通过样例进行演示. 多文件上传 1,代码编写 1)首先在 static 目录中创建一个 up ...

  6. P2762 太空飞行计划问题 (最小割)

    题意:n个实验 每个实验可获利ai元 做每个实验需要几个仪器 购买每个仪器有不同的花费 不同实验可能会用到同一个仪器 只用购买一次 求最大收益 题解:......................... ...

  7. CF1313C2 Skyscrapers (hard version)

    思路: 使用单调栈. 实现: 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 con ...

  8. Alternating Strings Gym - 100712D 简单dp && Alternating Strings II Gym - 100712L 数据结构优化dp

    比赛链接:https://vjudge.net/contest/405905#problem/D 题意: 给你一个长度为n的由0或1构成的串s,你需要切割这个串,要求切割之后的每一个子串长度要小于等于 ...

  9. 【noi 2.6_687】Color Tunnels(DP)

    P.S.o(︶︿︶)o 唉~虽然这题方程不难,但题目长,代码长,我花了超过3小时!(>﹏<)悲伤辣么大~~~ 谨此题解惠及众人,hh. 题意:给定长度为M的一串颜色序列,和平面上的N个颜色 ...

  10. poj1061青蛙的约会 (扩展欧几里德)

    Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事 ...