2022暑假每日一题笔记(五)
作者:互联网
T1--3715. 最少交换次数
给定一个 1∼N 的随机排列,要求一次只能交换相邻两个数,那么最少需要交换多少次才可以使数列按照从小到大排列呢?
请你求出一个待排序序列的最少交换次数和对应的逆序数列。
逆序数列:给定 n 个数 1,2,…,n 的一个排列 a1a2…an,令 bi 是数 i 在此排列中的逆序数,换句话说,bi 等于该排列中先于 i 又大于 i 的那些数的个数。数列 b1b2…bn 称为排列 a1a2…an 的逆序数列(inversion sequence)。
输入格式
第一行一个整数 N。
第二行一个 1∼N 的排列。
输出格式
第一行输出逆序数列,数之间用空格隔开。
第二行输出最少交换次数。
数据范围
1≤N≤1000
输入样例:
8
4 8 2 7 5 6 1 3
输出样例:
6 2 5 0 2 2 1 0
18
优质题解: https://www.acwing.com/solution/content/122074/。
常用的三种求逆序数的方法,暴力枚举,树状数组,归并排序。
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n;
int q[N],tmp[N],ans[N];
int merge_sort(int l,int r){
if (l >= r) return 0;
int mid = l+r>>1;
int res = merge_sort(l,mid) + merge_sort(mid+1,r);
int i = l,j = mid+1,k = 0;
while (i <= mid && j <= r){
if (q[i] <= q[j]) tmp[k++] = q[i++];
// 计算总的逆序数和每个元素的逆序数
else ans[q[j]] += mid-i+1,res += mid-i+1,tmp[k++] = q[j++];
}
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
for (int i = 0,j = l;j <= r;i ++,j ++) q[j] = tmp[i];
return res;
}
int main(){
cin >> n;
for (int i = 0;i < n;i ++) cin >> q[i];
int t = merge_sort(0,n-1);
for (int i = 0;i < n;i ++) cout << ans[q[i]] << ' ';
cout << '\n' << t << '\n';
return 0;
}
T2--3540. 二叉搜索树
输入一系列整数,利用所给数据建立一个二叉搜索树,并输出其前序、中序和后序遍历序列。
#include <bits/stdc++.h>
using namespace std;
int n;
bool st[1005];
struct TreeNode{
TreeNode *left,*right;
int val;
TreeNode(int x):val(x),left(NULL),right(NULL){}
}*root;
void insert(TreeNode *&root,int x){
if (!root) root = new TreeNode(x);
else if (x > root->val) insert(root->right,x);
else insert(root->left,x);
}
void pre_dfs(TreeNode *root){
if (!root) return;
cout << root->val << ' ';
pre_dfs(root->left);
pre_dfs(root->right);
return;
}
void mid_dfs(TreeNode *root){
if (!root) return;
mid_dfs(root->left);
cout << root->val << ' ';
mid_dfs(root->right);
}
void next_dfs(TreeNode *root){
if (!root) return;
next_dfs(root->left);
next_dfs(root->right);
cout << root->val << ' ';
}
int main(){
cin >> n;
int x;
for (int i = 0;i < n;i ++){
cin >> x;
if (!st[x]) insert(root,x); // 输入加上判重
st[x] = true;
}
pre_dfs(root);cout << '\n';
mid_dfs(root);cout << '\n';
next_dfs(root);
return 0;
}
T3--3619. 日期
今天是 2012 年 4 月 12 日星期四,编写程序,输入今天开始到 12 月 31 日之间的任意日期,输出那一天是星期几。
输入格式
共两行,第一行包含一个整数 m,表示询问日期的月份。
第二行包含一个整数 d,表示询问日期的为该月的第几天。
输出格式
输出询问日期是星期几。
注意,要用英文表示。
周一到周日的英文表示如下:
"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"
数据范围
4≤m≤12,
1≤d≤31,
保证日期合法。
输入样例:
5
20
输出样例:
Sunday
#include <bits/stdc++.h>
using namespace std;
string week[7] = {"Thursday","Friday","Saturday","Sunday","Monday","Tuesday","Wednesday"};
int month[9] = {30,31,30,31,31,30,31,30,31}; // 从4月开始
int calc(int m,int d){
int a = 4,b = 12,day = 0;
while (a < m-1){
a ++;
day += month[a-5];
}
if (a == m-1) day += month[a-4];
day += d-b;
return day;
}
int main(){
int m,d;
cin >> m >> d;
int day = calc(m,d);
cout << week[day % 7] << '\n';
return 0;
}
T4--3652. 最大连续子序列
给定 K 个整数的序列 {N0,N1,…,NK−1},其任意连续子序列可表示为 {Ni,Ni+1,…,Nj},其中 0≤i≤j<K。
最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列 {−2,11,−4,13,−5,−2},其最大连续子序列为 {11,−4,13} ,最大和为 20。
编写程序得到其中最大子序列的和并输出该子序列的第一个和最后一个元素的下标。
输入格式
输入包含多组测试数据。
每组数据占 2 行,第 1 行给出正整数 K。
第 2 行给出 K 个整数 N1,…,NK。
输出格式
每组数据输出一行结果,包含最大子序列的和以及子序列的第一个下标 i 和最后一个元素的下标 j。
所有元素下标为 0∼K−1。
如果最大子序列不唯一,则选择 i 最小的那个子序列,如果仍不唯一,则选择 i 最小的子序列中 j 最小的那个子序列。
若所有 K 个元素都是负数,则定义其最大和为 0,输出 0 0 0。
数据范围
1≤K≤10^5,
−10000≤Ni≤10000,
输入最多包含 10 组数据。
输入样例:
8
6 -2 11 -4 13 -5 -2 10
5
10 -10 10 -10 10
8
-1 -5 -2 3 -1 0 -2 0
4
-1 -2 -4 -3
输出样例:
27 0 7
10 0 0
3 3 3
0 0 0
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n,q[N],f[N];
int main(){
while (cin >> n){
for (int i = 1;i <= n;i ++) cin >> q[i];
int l = 1,r = 1,res = q[1];
for (int i = 1,j = 1;i <= n;i ++){
f[i] = max(f[i-1],0) + q[i];
// f[i]:0~i,1~i,...,i~i所有以i结尾的序列
// f[i-1]:0~i-1,1~i-1,...,i~i-1所有以i-1结尾的序列
// f[i] = f[i-1] + q[i] 或者 0 + q[i](不选之前的数)
if (f[i-1] < 0) j = i; // 上一步不存在最优解,左端点重新开始
// l,r分别对应左,右端点,当前比之前更优,更新答案
if (f[i] > res) l = j,r = i,res = f[i];
}
if (res < 0) res = 0,l = r = 1; // 全为负数
cout << res << ' ' << (l-1) << ' ' << (r-1) << '\n';
}
return 0;
}
T5--3644. 水仙花数
春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,它是这样定义的:
“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=13+53+33。
现在要求输出所有在 m 和 n 范围内的水仙花数。
输入格式
输入包含多组测试数据。
每组数据占一行,包含两个整数 m 和 n。
最后一行 0 0 表示输入结束。
输出格式
每组数据输出一行答案,从小到大输出所有位于 [m,n] 范围内的水仙花数,数之间用空格隔开,如果没有则输出 no。
数据范围
100≤m≤n≤999,
输入最多包含 10 组数据。
输入样例:
100 120
300 380
0 0
输出样例:
no
370 371
#include <bits/stdc++.h>
using namespace std;
int main(){
int m,n;
while (cin >> m >> n && n != 0){
int cnt = 0;
for (int i = m;i <= n;i ++){
int a = i / 100,b = i / 10 % 10,c = i % 10;
if (a*a*a + b*b*b + c*c*c == i){
cnt ++;cout << i << ' ';
}
}
if (!cnt) cout << "no\n";
else cout << '\n';
}
return 0;
}
T6--4518. 最低票价
在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。
在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出。
每一项是一个从 1 到 365 的整数。
火车票有三种不同的销售方式:
一张为期一天的通行证售价为 costs[0] 美元;
一张为期七天的通行证售价为 costs[1] 美元;
一张为期三十天的通行证售价为 costs[2] 美元。
通行证允许数天无限制的旅行。
例如,如果我们在第 2 天获得一张为期 7 天的通行证,那么我们可以连着旅行 7 天:第 2 天、第 3 天、第 4 天、第 5 天、第 6 天、第 7 天和第 8 天。
返回你想要完成在给定的列表 days 中列出的每一天的旅行所需要的最低消费。
输入格式
第一行包含一个整数 n,表示 days 数组的长度。
第二行包含 n 个整数,表示 days[i]。
第三行包含 3 个整数,表示 costs[i]。
输出格式
一个整数,表示旅行所需要的最低消费。
数据范围
1≤n≤365,
1≤days[i]≤365,
days 按顺序严格递增,
1≤costs[i]≤1000。
输入样例:
6
1 4 6 7 8 20
2 7 15
输出样例:
11
一眼DP,但是不会,参考y总。
当前f[i]
的计算有三种情况:
1.用天票覆盖,f[i] = f[i-1] + c1
2.用周票覆盖,f[i] = f[j7] + c1
,j7表示在days[i]的前面天数差值大于7天的最大天数
3.用月票覆盖,f[i] = f[j30] + c1
,j30表示在days[i]的前面天数差值大于30天的最大天数
双指针 + DP。(不用双指针也可以直接搜索或用二分来加速搜索)
#include <bits/stdc++.h>
using namespace std;
const int N = 368;
int n,days[N],f[N];
int c1,c7,c30;
int main(){
cin >> n;
for (int i = 1;i <= n;i ++) cin >> days[i];
cin >> c1 >> c7 >> c30;
for (int i = 1,j7 = 0,j30 = 0;i <= n;i ++){
// 双指针找到j7的位置,如:1 2 3 4 5 6 7 8,i = 8对应的j7 = 1
while (j7 <= n && days[i]-days[j7+1] >= 7) j7 ++;
while (j30 <= n && days[i]-days[j30+1] >= 30) j30 ++;
f[i] = min({f[i-1] + c1,f[j7] + c7,f[j30] + c30}); // 两个以上的值取min!
}
cout << f[n] << '\n';
return 0;
}
标签:输出,2022,int,days,笔记,暑假,root,输入,cout 来源: https://www.cnblogs.com/grant-drew/p/16487890.html