第9周cf刷题(dp)
Problems(1300-1600)
an ac a day keeps the doctor away
Gas Pipeline (1500)
2019.10.28
题意:
管道工人需要在一段凹凸不平的道路上铺管子,给一串长度为n的01序列描述地形,1表示一定要把水管用钢管架高在离地面2个单位,0表示水管离地面高度可以为1,也可以为2.
在转折的地方需要额外花费1单位的水管,给定水管和钢管的价格a,b;问最少需要花费多少钱
思路:线性DP,用dp[i] [j] 表示前j列在第j列在第i层时的最小花费(i = 0表示离地高度为1,i = 1表示离地高度为2),很容易想到状态转移方程。
注意点:当该点为0时,如果前一个点为1那么必须继续保持离地高度为2(我也不知道为什么,样例的规则就是这样)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const ll inf = 0x3f3f3f3f3f3f3f3f;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
int t,n;
ll a,b;
char s[maxn];
ll dp[2][maxn];
int main()
{
t = read();
while(t--){
n = read();scanf("%lld %lld",&a,&b);
scanf("%s",s);
for(int i = 0;i < 2;i++){ //初始化
for(int j = 0;j <= n;j++) dp[i][j] = inf;
}
dp[0][0] = b;
for(int i = 1;i < n;i++){
if(s[i] == '0' && s[i - 1] == '0'){
dp[0][i] = min(dp[1][i - 1] + 2 * a + b,dp[0][i - 1] + a + b);
dp[1][i] = min(dp[1][i - 1] + a + 2 * b,dp[0][i - 1] + 2 * a + 2 * b);
} else{
dp[1][i] = min(dp[1][i - 1] + a + 2 * b,dp[0][i - 1] + 2 * a + 2 * b);
}
// cout << dp[0][i] << " " << dp[1][i] << endl;
}
//最后处理第n列
dp[0][n] = min(dp[1][n - 1] + 2 * a + b,dp[0][n - 1] + a + b);
printf("%lld\n",dp[0][n]);
}
return 0;
}
Block Adventure(1300)
2019.10.28
题意:
从起点到终点有 n 个格子,每块高度 h[i],初始时背包有m块方块,从 i 跳到 i+1 有三种选择,1. 把背包的一个方块放到当前的格子上;2. 把当前格子的一个方块放到背包里;3.跳到下一块。
前两种选择可以进行任意多次
只有当 | h[i] - h[i+1] | <= k 才能跳到下一块。 问是否能跳到终点?
思路:贪心+线性模拟,能拿就尽可能拿更多的石头(但注意最多只能拿完),不能拿就放最少回去使其通过,如果石头为负数就不符合条件.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
int t,n,m,k;
int h[105];
int main()
{
t = read();
while(t--){
n = read(); m = read(); k = read();
for(int i = 0;i < n;i++) h[i] = read();
bool ok = 1;
for(int i = 1;i < n;i++){
if(h[i - 1] - h[i] >= -k) m += min(h[i - 1] - h[i] + k,h[i - 1]);
else{
if(h[i] - h[i - 1] - m <= k) m -= (h[i] - h[i - 1] - k);
else {ok = 0;break;}
}
}
if(ok) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
Basketball Exercise (1400)
2019.10.29
题意:
输入n,给出两组均为 n个数字的数组a和b,轮流从a和b数组中取出一个数字(可以不取),要求严格按照当前所选数字的数组下标比上一个所选数字的数组下标更大,计算能够取出的数字加起来的总和最大能为多少。
思路:线性DP,又是这种上下两行条件约束的递推题,处理好约束条件和状态转移方程即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
int n;
ll h[2][maxn],dp[2][maxn];
int main()
{
n = read();
for(int i = 0;i < 2;i++){
for(int j = 1;j <= n;j++) scanf("%lld",&h[i][j]);
}
dp[0][1] = h[0][1]; dp[1][1] = h[1][1];
for(int j = 2;j <= n;j++){
for(int i = 0;i < 2;i++){
dp[i][j] = max(dp[i][j - 1],dp[i ^ 1][j - 1]); //不选
dp[i][j] = max(dp[i ^ 1][j - 1],max(dp[i][j - 2],dp[i ^ 1][j - 2])) + h[i][j]; //选
}
}
printf("%lld",max(dp[0][n],dp[1][n]));
return 0;
}
RGB Substring (1600)
2019.10.29
人类的智慧!这题好好总结!
题意:
有一个“RGB……”无限循环的母串,q组样例,每组一个给出一个长度为n的字符串,让你通过更改该串的某个字符构造一个长度为k的母串的子串,求满足要求的最少更改次数。
思路:思维+前缀和,母串的样板串只有三种:"RGB……" "GBR……" "BRG……",分别统计这三种情况下母串和子串的不匹配贡献的前缀和,即如果对应位置不同,前缀和++,否则不变。然后暴力枚举所有长度为k的区间和,找出最小值即为答案。时间复杂度O(n).
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
int q,n,k,ans;
char s[maxn];
int a[3][maxn];
string t = "RGB";
int main()
{
q = read();
while(q--){
n = read(); k = read();
scanf("%s",s);
ans = maxn;
for(int i = 0;i < n;i++){
for(int j = 0;j < 3;j++){
if(s[i] != t[(i + j) % 3]) a[j][i + 1] = a[j][i] + 1;
else a[j][i + 1] = a[j][i];
}
}
for(int i = 0;i + k <= n;i++){
for(int j = 0;j < 3;j++){
ans = min(ans,a[j][i + k] - a[j][i]);
}
}
printf("%d\n",ans);
}
return 0;
}
WOW Factor(1300)
2019.10.29
题意:给出一个字符串s,只含v和o,求其中wow对数量,w由两个v组成,v只能相邻。
思路:前缀和统计w对数即可,答案就是每个o两端w对数的积的总和。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
char s[maxn];
int a[maxn];
ll ans;
int main()
{
scanf("%s",s);
int len = strlen(s);
//前缀和统计'w'对数
for(int i = 0;i < len;i++){
if(s[i] == 'v' && s[i - 1] == 'v' && i != 0) a[i + 1] = a[i] + 1;
else a[i + 1] = a[i];
}
for(int i = 0;i < len;i++){
if(s[i] == 'o') ans += 1LL * a[i] * (a[len] - a[i]);
}
cout << ans << endl;
return 0;
}
Lose it!(1300)
2019.10.30
题意:给出一串数n个,只含4,8,15,16,23,42,从中删去k个数,使数列长度能被6整除并且其子序列(n - k) / 6个都满足给出的形式[4,8,15,16,23,42]。求k的最小值
思路:贪心+计数,需要一定的思维,用seq[0]代表[4],seq[1]代表[4,8]……seq[5]代表[4,8,15,16,23,42],贪心进行计数,遇到4直接seq[0]++,其他情况贪心,优先补足长的序列,短的序列--,最后答案就是n - seq[5] * 6。
瞎搞貌似也过了,但是感觉会被hack。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 5;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
vector<int> p({4,8,15,16,23,42});
int n;
int main()
{
n = read();
vector<int> a(n);
for(int i = 0;i < n;i++){
a[i] = read();
a[i] = lower_bound(p.begin(),p.end(),a[i]) - p.begin(); //类似离散化
}
vector<int> seq(6);
for(int i = 0;i < n;i++){
if(a[i] == 0) seq[0]++;
else{
int x = a[i];
if(seq[x - 1] > 0) seq[x - 1]--,seq[x]++;
}
}
printf("%d\n",n - seq[5] * 6);
return 0;
}
Candies! (1400)
题意:给定n个数,每次查询一个区间\([l,r]\)。对这个区间内的数,相邻两个数之和超过10,则得到一个candy,然后将他们之和取模10的结果作为新的数。
一共操作\(l−r\)次,问这个区间得到的candy数。
思路:一种思路是可以发现,实际上candy数是\(⌊区间和/10⌋\),而新得到的数实际上是/10之后的余数部分。
每次操作的过程其实可以看成是两两求和然后取/10的商,然后把余数部分留给下一次操作。
所以ans\([l,r]\)=\(\frac{⌊a_l+a_{l+1}~+...+a_r⌋ }{10}\) 。
另一种思路是用倍增的思想进行dp。
\(dp[i][j]\)表示以\(i\)为起点,长度为\(2^j\)的区间所得到的candy数量。因为转移的时候还需要知道当前操作之后的数是什么,所以用\(sum[i][j]\)记录对应操作后的数。
\(dp[i][j]=dp[i][j−1]+dp[i+2^{j−1}][j−1]+(sum[i][j−1]+sum[i+2^{j−1}][j−1]≥10)\)
$sum[i][j] = (sum[i][j - 1] + sum[i + 2^{j - 1}][j - 1]) $ % \(10\)
倍增解法
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
inline int read(){
int f = 1,x = 0; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - 48;ch = getchar();}
return f * x;
}
int n,q,l,r;
int a[maxn];
int f[maxn][25],sum[maxn][25];
void gao(){
for(int i = 1;i <= n;i++){
f[i][0] = 0;
sum[i][0] = a[i];
}
for(int j = 1;(1 << j) <= n;j++){
for(int i = 1;i + (1 << (j - 1)) <= n;i++){
f[i][j] = f[i][j - 1] + f[i + (1 << (j - 1))][j - 1] +
((sum[i][j - 1] + sum[i + (1 << (j - 1))][j - 1]) >= 10);
sum[i][j] = (sum[i][j - 1] + sum[i + (1 << (j - 1))][j - 1]) % 10;
}
}
}
int query(int l,int r){return f[l][(int)log2(r - l + 1)];}
int main()
{
n = read();
for(int i = 1;i <= n;i++) a[i] = read();
gao();
q = read();
while(q--){
l = read(); r = read();
printf("%d\n",query(l,r));
}
return 0;
}
智慧解法
#include <bits/stdc++.h>
const int maxn = 1e5 + 5;
int n, q;
int num[maxn], sum[maxn];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &num[i]);
sum[i] = sum[i - 1] + num[i];
}
scanf("%d", &q);
while(q--){
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", (sum[r] - sum[l - 1]) / 10);
}
return 0;
}
Diverse Garland(1400)
2019.10.31
题意:给出一个只含R,G,B的字符串,改变其中的字符,使相邻两个字符都不相同,求最少改变量?
思路:模拟即可,遇到和前面一个字符相同的字符,把它改变为和前后相邻字符都不相同的字符即可,统计答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int n,ans;
char s[maxn];
string k = "RGB";
int main()
{
scanf("%d",&n); scanf("%s",s + 1);
for(int i = 2;i <= n;i++){
if(s[i] == s[i - 1]){
for(int j = 0;j < 3;j++){
if(k[j] != s[i - 1] && k[j] != s[i + 1]){s[i] = k[j];ans++;break;}
}
}
}
cout << ans << endl;
for(int i = 1;i <= n;i++) cout << s[i];
cout << endl;
return 0;
}
Dima and a Bad XOR(1600)
2019.10.31
题意:给你一个n*m的矩阵,每一行你可以选一个数,在每一行都选数的前提下,能不能使每一行选的这些数的异或值不为0,如果存在相应方案,输出这些方案对应的每一行数的下标。
思路:数学+思维,首先将每一行第一列的数异或起来,若不为0,输出答案;否则对于每一行,如果能找出一个与该行第一列的数不相同的数,则存在对应方案,如果找不到,说明这一行所有数相同,该行无法修改。如果所有行都不满足条件,则没有方案,否则必然存在一种方案使得异或值不为0.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 505;
int n,m;
int a[maxn][maxn];
int main()
{
scanf("%d %d",&n,&m);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++) scanf("%d",&a[i][j]);
}
int ans = 0;
for(int i = 1;i <= n;i++) ans ^= a[i][1];
if(ans){
cout << "TAK" << endl;
for(int i = 1;i <= n;i++) cout << 1 << " ";
cout << endl;
} else{
bool ok = 0;
int pos = -1,row = -1;
for(int i = 1;i <= n;i++){
if(ok) break;
for(int j = 2;j <= m;j++){
if(a[i][j] != a[i][1]){
row = i,pos = j;
ok = 1;
break;
}
}
}
if(ok){
cout << "TAK" << endl;
for(int i = 1;i <= n;i++){
if(i == row) cout << pos << " ";
else cout << 1 << " ";
}
cout << endl;
} else{
cout << "NIE" << endl;
}
}
}
第9周cf刷题(dp)的更多相关文章
- 第十六周oj刷题——Problem I: 改错题:类中私有成员的訪问
Description 改错题: 设计一个日期类和时间类,并编写全局函数display用于显示日期和时间. 要求:display函数作为类外的普通函数,而不是成员函数 在主函数中调用display函数 ...
- 第十六周oj刷题——Problem E: B 构造函数和析构函数
Description 在建立类对象时系统自己主动该类的构造函数完毕对象的初始化工作, 当类对象生命周期结束时,系统在释放对象空间之前自己主动调用析构函数. 此题要求: 依据主程序(main函数)和程 ...
- 【CF刷题】14-05-12
Round 236 div.1 A:只需要每个点连接所有比他大的点,知道边用完为止. //By BLADEVIL #include <cmath> #include <cstdio& ...
- 第十七周oj刷题——Problem B: 分数类的四则运算【C++】
Description 编写分数类Fraction,实现两个分数的加.减.乘和除四则运算.主函数已给定. Input 每行四个数,分别表示两个分数的分子和分母,以0 0 0 0 表示结束. Outpu ...
- 第十六周oj刷题——Problem J: 填空题:静态成员---计算学生个数
Description 学生类声明已经给出.在主程序中依据输入信息输出实际建立的学生对象个数,以及全部学生对象的成绩总和. Input 学生个数 相应学生个数的学生信息(姓名 年龄 成绩) ...
- CF刷题-Codeforces Round #481-G. Petya's Exams
题目链接:https://codeforces.com/contest/978/problem/G 题目大意:n天m门考试,每门考试给定三个条件,分别为:1.可以开始复习的日期.2.考试日期.3.必须 ...
- CF刷题-Codeforces Round #481-F. Mentors
题目链接:https://codeforces.com/contest/978/problem/F 题目大意: n个程序员,k对仇家,每个程序员有一个能力值,当甲程序员的能力值绝对大于乙程序员的能力值 ...
- CF刷题-Codeforces Round #481-D. Almost Arithmetic Progression
题目链接:https://codeforces.com/contest/978/problem/D 题解: 题目的大意就是:这组序列能否组成等差数列?一旦构成等差数列,等差数列的公差必定确定,而且,对 ...
- 第十五周oj刷题——Problem M: C++习题 矩阵求和--重载运算符
Description 有两个矩阵a和b,均为2行3列.求两个矩阵之和.重载运算符"+",使之能用于矩阵相加(如c=a+b). 重载流插入运算符"<<&quo ...
随机推荐
- kubernets安装rabbitmq集群.
RabbitMQ集群的两种模式 1)普通模式:默认的集群模式,队列消息只存在单个节点上 2)镜像模式:队列为镜像队列,队列消息存在每个节点上 配置同步: 配置同步: 1.Ha mode 同步模式,以下 ...
- [题解] [Code+#1]Yazid 的新生舞会
题面 题解 upd : \(cnt_i\) 代表值为 \(i\) 的个数 我们可以暴力枚举众数 \(k\) 把等于 \(k\) 的赋值成 1 , 不等于 \(k\) 的赋值成 -1 这样原序列就变成了 ...
- 小程序开发:用原生还是选框架(wepy/mpvue/uni-app/taro)?
小程序开发:用原生还是选框架(wepy/mpvue/uni-app/taro)? 自 2017-1-9微信小程序诞生以来,历经2年多的迭代升级,已有数百万小程序上线,成为继Web.iOS.Androi ...
- 修改oracle用户登录密码
运行sqlplus进入输入密码界面 用户名输入: connect as sysdba 密码:这边乱输就可以了 然后进行输入下面的命令: 修改密码命令 alter user system identif ...
- GA函数优化
一.遗传算法简介 遗传算法(Genetic Algorithms,GA)是1962年美国人提出,模拟自然界遗传和生物进化论而成的一种并行随机搜索最优化方法. 与自然界中“优胜略汰,适者 ...
- Linux 系统配置永久性时间同步
临时修改系统时间(reboot后系统时间恢复): date 查看系统时间 date -s "设置的系统时间" 永久性修改系统时间: date 查看系统时间 hwclock --s ...
- Flutter设置Container的最大最小宽高
Flutter中设置Container宽高可直接通过width和height属性来设置:如下 Container( width: 100, height: 100, color: Colors.red ...
- Postgresql - MATERIALIZED VIEW
MATERIALIZED VIEWPG 9.3 版本之后开始支持物化视图.View 视图:虚拟,不存在实际的数据,在查询视图的时候其实是对视图内的表进行查询操作. 物化视图:实际存在,将数据存成一张表 ...
- cmder的segmentation fault错误修复
Segmentation fault 现场还原 问题出现的原因是我在 cmder的命令行里执行了cmder /register ALL命令,本意是把cmder放到右键菜单里去的 但我没想到的是,各种不 ...
- 仙剑奇侠传1系列:2.编译主程序SDLPAL及SDL
上一篇:仙剑奇侠传1系列:1.本地运行环境及兼容性设置 介绍 仙剑奇侠传1是dos时代的经典游戏,相信以下图片能勾起大家的很多回忆. sdlpal是仙剑奇侠传1的主程序.github项目sdlpa ...