- 有unsigned long long 这种类型
bitset< n > b
- string转换为int
string s="123";
int i=stoi(s);//or i=atoi(s.c_str());
- 关于如何通过天数计算年月日
#include <bits/stdc++.h>
using namespace std;
const int Q = 1e5 + 5;
const int N = 146097;//以400年为周期,每400年恰好有146097天
int d[N], m[N], y[N], T;
typedef long long ll;
ll n, t;
int md(int y,int m){//计算格里高利y年m月的天数
if (m == 2)
return y % 4 ? 28 : y % 100 ? 29 : y % 400 ? 28 : 29;
else
return m == 4 || m == 6 || m == 9 || m == 11 ? 30 : 31;
}
int main() {
m[0] = d[0] = 1;
for (int i = 1; i < N; i++) {
d[i] = d[i - 1] + 1, m[i] = m[i - 1], y[i] = y[i - 1];
if (d[i] > md(y[i], m[i])) d[i] = 1, ++m[i];
if (m[i] > 12) m[i] = 1, ++y[i];
}
cin >> T;
for (int i = 0; i < T; i++) {
cin >> n;
if (n > 2299160) {//格里高利日历
n -= 2159351;//以公元1200作为格里高利的起点,但是我算出来是2159358,而且对于1582.10.5-1582.10.14这些天不知道为什么并不需要特殊处理
t = n / N * 400 + 1200;//对应400周期中某个的起始年
n %= N;
}
else {
t = n / 1461 * 4 - 4712;//1461是儒略年4年周期的天数 这里不能写为-4713 后面输出时删除1!
n %= 1461;
}
if (t + y[n] > 0) cout << d[n] << " " << m[n] << " " << t + y[n] << endl;
else cout << d[n] << " " << m[n] << " " << 1 - t - y[n] << " BC" << endl;
}
}
- 在进行二分递归求解时,不一定非得要左右端点参数进行递归,如果二分递归公式形如:
可以将自变量作为参数,而如果相加的两个f可能被重复求取,可以使用map(或者数组)进行存储结果
ll f(ll x) {
if (x < 2 * k + 2) return 1;
if (mp[x]) return mp[x];
return mp[x]=f(x / 2) + f(x - x / 2);
}
- C++常见排序
#include <bits/stdc++.h>
using namespace std;
int a[10] = { 0,2,4,9,6,7,8,3,1,5 };
int n = 10;
/*从小到大排序*/
//插入排序--时间复杂度为O(n²),空间复杂度为O(1)
void insertSort() {
int i, j;
for (i = 1; i < n; i++) {
if (a[i] < a[i-1]) {//a[i] not a[i+1]
int tmp = a[i];
for (j = i - 1; j > 0 && tmp < a[j]; j--) {
a[j + 1] = a[j];
}
a[j + 1] = tmp;
}
}
}
//桶排序--当需要排序的数较小时,可以很快O(n),当然也可先按照范围分桶,然后再在每个桶内进行快速排序或者其他时间复杂度较低的排序
void bucketSort() {
int t[10];
memset(t, 0, sizeof(t));
for (int i = 0; i < n; i++) {
t[a[i]]++;
}
for (int i = 0; i <= 9; i++) {//需要排序的数的上下界
while (t[i]--)
cout << i << " ";
}
}
//冒泡排序--时间复杂度为n²
void bubbleSort() {
for (int i = 0; i < n - 1; i++) { //挑选最大值到最后面
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
swap(a[j], a[j + 1]);
}
}
}
}
//选择排序--时间复杂度为O(n²),空间复杂度为O(1)
void selectSort() {//找到最小值,并记录其位置,然后和第i个元素交换,每次进行一个循环就找到一个最小值
for (int i = 0; i < n; i++) {
int k = i;
for (int j = k + 1; j < n; j++) {
if (a[j] < a[k])
k = j;//找到更小
}
swap(a[i], a[k]);
}
}
//快速排序,平均时间复杂度为o(nlogn),空间复杂度为o(logn)
void quickSort(int l, int r, vector<int>& v) {
if (l >= r)
return;
int i = l, j = r;
int base = v[l];
while (i < j) {
while (v[j] >= base && i < j) //一定要写等于号
j--;
while (v[i] <= base && i < j)
i++;
if (i < j)
swap(v[i], v[j]);
}
swap(v[l], v[i]);
quickSort(l, i - 1, v);
quickSort(i + 1, r, v);
}
//归并排序--时间复杂度为O(nlong) 空间复杂度为O(n)
void merge(int l, int mid, int r, vector<int>& v) {
int p1 = l, p2 = mid + 1;
vector<int> tmp(r - l + 1);
int i = 0;
while (p1 <= mid && p2 <= r) {
tmp[i++] = v[p1] <= v[p2] ? v[p1++] : v[p2++];
}
while (p1 <= mid)
tmp[i++] = v[p1++];
while (p2 <= r)
tmp[i++] = v[p2++];
for (int j = l; j <= r; j++)
v[j] = tmp[j - l];
}
void mergeSort(int l, int r, vector<int>& v) {
if (l >= r)
return;
int mid = l + (r - l) / 2;
mergeSort(l, mid, v);
mergeSort(mid + 1, r, v);
merge(l, mid, r, v);
}
//堆排序--时间复杂度为O(nlogn),空间复杂度为O(1)
void adjust(vector<int>& v, int s, int m) {
//v[s..m],其中出s之外满足堆的定义,调整s使得H[s..m]成为最大堆
int rc = v[s];
for (int j = 2 * s; j <= m; j *= 2) {//沿值较大的孩子节点向下筛选
if (j < m && v[j] < v[j + 1]) j++;
if (rc >= v[j]) break;
v[s] = v[j], s = j;
}
v[s] = rc;
}
void heapSort(vector<int>& v) {
int len = v.size();
for (int i = len / 2; i >= 0; --i)
adjust(v, i, len - 1);
for (int i = len - 1; i >= 1; --i) {
swap(v[i], v[0]);
adjust(v, 0, i - 1);
}
}
- 关于二分查找
int find_first_equal(vector<int>& v, int target) {
if (v.size() == 0)
return -1;
int l = 0, r = v.size() - 1;
int ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (v[mid] == target) {
ans = mid;
r = mid - 1;
}
else if (v[mid] > target) r = mid - 1;
else l = mid + 1;
}
return ans;
}
//查找最后一个等于target的数
int find_last_equal(vector<int>& v, int target) {
if (v.size() == 0)
return -1;
int l = 0, r = v.size() - 1;
int ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (v[mid] == target) {
ans = mid;
l = mid + 1;
}
else if (v[mid] > target) r = mid - 1;
else l = mid + 1;
}
return ans;
}
//找到第一个大于等于x的位置
int find_first_LG(vector<int>& v, int x) {
int l = 0, r = v.size() - 1;
int ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (v[mid] >= x) {
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
return ans;
}
- cout输出格式
//对齐和宽度
int a=12345;
cout << setiosflags(ios::left) << setw(15) << a << endl;
cout << setiosflags(ios::right) << setw(15) << a << endl;
//也可以直接写为cout<<left<<setw(15)<<a<<right<<setw(15)<<a<<endl;
//取消对齐
cout<<resetiosflags(ios::left);
//设置精度
double a=123.456789;
cout<<setprecision(3)<<a<<endl;//123
//保留小数点位数
cout<<fixed<<setprecision(2)<<3.1415926<<endl;//保留两位
//进制输出
//dec-十进制
//hex-十六进制
//oct-八进制
int a=256;
cout<<hex<<a<<endl;//400,不带前缀
cin<<hex<<a;
//设置填充字符--setfill()
int a=12345;
cout<<setfill('0')<<setw(10)<<a<<endl;//默认右对齐
- dp(O(n²))和数组(O(nlogn))求解最长非上升序列和最长上升序列
洛谷—导弹拦截
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
//最长下降子序列--1. 使用dp,复杂度为O(n²)
//dp[i]表示以a[i]结尾的最长的下降子序列的长度
//dp[i]=max(dp[j])+1 (j<i&&a[j]>=a[i])
//如何确定有多少个这样的最长子序列呢?
//为最长上升序列的长度
const int N = 1e5 + 5;
int a[N], d1[N], d2[N], n = 0;//d1,d2分别存放非上升序列和上升序列
int main() {
/*以下为dp做法,但是不知道为什么无法通过全部的测试,有两个WA,其他有些为TLE*/
/*
int cnt = 1;
int dp1[N], dp2[N];//分别记录最长不上升序列和最长上升序列
int a[N];
ios::sync_with_stdio(false);
while (cin >> a[cnt]) {
dp1[cnt] = dp2[cnt++] = 1;
}
cnt -= 1;
for (int i = 1; i <= cnt; i++) {
for (int j = 1; j < i; j++)
if (a[j] >= a[i])
dp1[i] = max(dp1[i], dp1[j] + 1);
for (int j = 1; j < i; j++)
if (a[j] < a[i])
dp2[i] = max(dp2[i], dp2[j] + 1);
}
int max1 = -1, max2 = -1;
for (int i = 1; i <= cnt; i++) {
max1 = max(max1, dp1[i]);
max2 = max(max2, dp2[i]);
}
cout << max1 <<"\n" << max2;
*/
/*下面为复杂度为O(nlogn)的算法,也是求解一个最长非上升序列和最长上升序列*/
ios::sync_with_stdio(false);
while (cin >> a[++n]);
--n;
int len1 = 1, len2 = 1;//分别记录d1和d2的长度
d1[1] = d2[1] = a[1];
for (int i = 2; i <= n; i++) {
if (a[i] <= d1[len1]) d1[++len1] = a[i];
else {
//由于这个函数要求是升序,而本身d1是降序,所以需要改变比较器的排序方式
int p = upper_bound(d1 + 1, d1 + len1 + 1, a[i], greater<int>()) - d1;//找到第一个大于a[i]的元素的下标,不能是等于,否则会覆盖,和前面if的比较是相对应的
d1[p] = a[i];
}
if (a[i] > d2[len2]) d2[++len2] = a[i];
else {
int p = lower_bound(d2 + 1, d2 + len2 + 1, a[i]) - d2;//找到第一个大于等于a[i]的元素的下标
d2[p] = a[i];
}
}
cout << len1 << endl << len2;
}
- 前缀和
洛谷P3406
#include <bits/stdc++.h>
using namespace std;
//A-纸质 B-IC车费 C-工本费
const int N = 1e5 + 5, M = 1e5 + 5;;
int p[M];
int a[N], b[N], c[N];
int cnt[N];
int sum[N];//前缀和
typedef long long ll;
ll ans;
int n, m;
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> p[i];
}
//需要先统计此次出差需要经过每段铁路的数量人,然后才能判断是电子还是纸质
for (int i = 1; i <= m - 1; i++) {
cnt[min(p[i], p[i + 1])]++;//如果使用for循环遍历每一段地铁,会超时
cnt[max(p[i], p[i + 1])]--;
}
for (int i = 1; i <= n - 1; i++) {
cin >> a[i] >> b[i] >> c[i];
sum[i] = sum[i - 1] + cnt[i];
if (sum[i]) {
ll tmp = 0;
ll paper= (ll)a[i] * (ll)sum[i];
ll ic = (ll)c[i] + (ll)sum[i] * b[i];
ans += (min(paper, ic));
}
}
cout << ans;
}
- 快读
int read(){
int re=0;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){
re=re*10+ch-'0';
ch=getchar();
}
return re;
}
- 图(树)中的链式前向星
int head[N],tot;//head[u]为起始的u射出的边的编号
struct Edge{
int v,w,nxt;
}e[M];//如果是无向图,需要乘以2,并加入两次
void add(int u,int v){
e[++tot].v=v;
e[tot].nxt=head[u];
head[u]=tot;
}//输入边时,从序号1开始
- 图算法
//Floyd算法--计算图中任意两个点的最短距离
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
//dijkstra算法--计算没有负边的单源最短路问题
```cpp
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5, maxm = 1e5 + 5;
const int inf = 5 * 1e8;
int m, n;
int head[maxn], dis[maxn], vis[maxn],tot;
struct Edge {
int v, w, nxt;
}e[maxm];
void add(int u, int v, int w) {
e[++tot].v = v;
e[tot].w = w;
e[tot].nxt = head[u];
head[u] = tot;
}
priority_queue<pair<int, int> > q;//y,dis,默认大根堆,放入负数变成小根堆
int dijktra(int s) {
while (q.size()) q.pop();
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i++) dis[i] = inf;
q.push({ 0,s });
dis[s] = 0;
while (!q.empty()) {
int x = q.top().second;
q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = x; i; i = e[i].nxt) {
int y = e[i].v, w = e[i].w;
if (dis[y] > dis[x] + w) {
dis[y] = dis[x] + w;
q.push({ y,-dis[y] });
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
dijktra(1);
return 0;
}
//如果是求最大路,不需要vis数组
int dijktra(int s) {
while (q.size()) q.pop();
for (int i = 1; i <= n; i++) dis[i] = -inf;
q.push({ 0,s });
dis[s] = 0;
while (!q.empty()) {
int x = q.top().second, v = q.top().first;
q.pop();
if (v<dis[x]) continue;
for (int i = x; i; i = e[i].nxt) {
int y = e[i].v, w = e[i].w;
if (dis[y] < dis[x] + w) {
dis[y] = dis[x] + w;
q.push({ y,dis[y] });
}
}
}
}
//spfa--bellmanford的队列优化算法,不能有负环
queue<int> q;
int cnt[maxn];
void spfa(int s) {
while (q.size()) q.pop();
for (int i = 1; i <= n; i++)
vis[i] = cnt[i] = 0, dis[i] = inf;
q.push(s);
vis[s] = 1, dis[s] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
vis[x] = 0;
for (int i = x; i; i = e[i].nxt) {
int y = e[i].v;
if(dis[y] > dis[x]+e[i].w){
dis[y] = dis[x] + e[i].w;
cnt[y] = cnt[x] + 1;
if (cnt[y] >= n) {
//负环
}
if (!vis[y]) {
q.push(y);
vis[y] = 1;
}
}
}
}
}
- 最近公共祖先
const int N = 5e5 + 5, M = 5e5 + 5;
struct Edge {
int v, nxt;
}e[N<<1];//无向图,*2
int head[N], tot;
int fa[N][23];//表示fa[i][j]表示第i个节点的2的j次方级祖先
int depth[N], lg[N];//第i级节点的深度和log(i)
int n, m, s;
void add(int x, int y) {//x->y
e[++tot].v = y;
e[tot].nxt = head[x];
head[x] = tot;
}
void getLog(void) {
for (int i = 1; i <= n; i++)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
return;
}
void dfs(int x,int fath) {
fa[x][0] = fath; depth[x] = depth[fath] + 1;
for (int j = 1; j <= lg[depth[x]]; j++) {
fa[x][j] = fa[fa[x][j - 1]][j - 1];//x的2^j祖先是x的2^(j-1)祖先的2^(j-1)祖先
}
for (int i = head[x]; i; i = e[i].nxt) {//无向图,有其他的边指向x
if (e[i].v != fath) dfs(e[i].v, x);
}
return;
}
int LCA(int x, int y) {
//调整深度,假设x>y
if (depth[x] < depth[y])
swap(x, y);
while (depth[x] > depth[y])
x = fa[x][lg[depth[x] - depth[y]] - 1];//先跳到同一深度
if (x == y)
return x;
for (int k = lg[depth[x]] - 1; k >= 0; --k)
if (fa[x][k] != fa[y][k])
x = fa[x][k], y = fa[y][k];
return fa[x][0];
}
- 单源最短路时,如果要求多个点到源点的距离,可以利用反图求源点到多个点的距离,反图可以使用+n的偏移,放在一个数据结构中(大小*2)。
- 求s-t的最小生成树中最大边的权值:在使用Kruskal算法for循环加入边unite时,判断s和t是否连通,如果是,则此时加入的边的权值即为所求。
- 无向图,Kruskal并不需要加入双向边。
- 线段树
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int M = 1e5 + 5;
typedef long long ll;
ll Sum[maxn << 2], Add[maxn << 2];//求和,ADD-懒惰标记
int A[maxn], n, m;//存原数组及下标n
void PushUp(int rt) {//更新节点信息,此处为求和
Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
}
//建树
void Build(int l, int r, int rt) {
//l,r表示当前节点区间,rt表示当前节点编号
if (l == r) {//到达叶节点
Sum[rt] = A[l];
return;
}
int m = (l + r) >> 1;
Build(l, m, rt << 1);
Build(m + 1, r, rt << 1 | 1);
PushUp(rt);
}
//点修改,假设A[L] +=C
void Update(int L, int C, int l, int r, int rt) {
if (l == r) {
Sum[rt] += C;
return;
}
int m = (l + r) >> 1;
if (L <= m)
Update(L, C, l, m, rt << 1);
else
Update(L, C, m + 1, r, rt << 1 | 1);
PushUp(rt);//子节点更新了,本节点也要更新
}
//区间查询--询问A[L,R]的和
//1. 下推标记
void PushDown(int rt, int ln, int rn) {
//ln,rn为左子树和右子树数字数量
if (Add[rt]) {
//下推
Add[rt << 1] += Add[rt];
Add[rt << 1 | 1] += Add[rt];
//修改子节点的Sum使之与对应的Add相对应
Sum[rt << 1] += Add[rt] * ln;
Sum[rt << 1 | 1] += Add[rt] * rn;
//清除本节点标记
Add[rt] = 0;
}
}
//2. 区间查询
ll Query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return Sum[rt];
}
int m = (l + r) >> 1;
PushDown(rt, m - l + 1, r - m);
//累计答案
ll ans = 0;
if (L <= m)
ans += Query(L, R, l, m, rt << 1);
if (R > m)
ans += Query(L, R, m + 1, r, rt << 1 | 1);
return ans;
}
//区间修改A[L,R] += C
void Update(int L, int R, int C, int l, int r, int rt) {
//L,R表示操作区间,l,r表示当前区间,rt当前节点编号
if (L <= l && r <= R) {//当前区间为操作区间的子区间,打上懒惰标记,表示其子树不再需要考虑
Sum[rt] += (ll) C * (r - l + 1);
Add[rt] += C;
return;
}
int m = (l + r) >> 1;
PushDown(rt, m - l + 1, r - m);//下推标记
//否则,考虑子树,有交集才递归
if (L <= m)
Update(L, R, C, l, m, rt << 1);
if (R > m)
Update(L, R, C, m + 1, r, rt << 1 | 1);
PushUp(rt);//更新本节点信息;
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> A[i];
Build(1, n, 1);
for (int i = 1; i <= m; i++) {
int j;
cin >> j;
if (j == 1) {//区间加k
int l, r, c;
cin >> l >> r >> c;
Update(l, r, c, 1, n, 1);
}
else {
int l, r;
cin >> l >> r;//查询和
cout << Query(l, r, 1, n, 1) << endl;
}
}
}
- 布尔表达式求值
#include <bits/stdc++.h>
using namespace std;
const int TREE_N = 5e5 + 5;
const int N = 1e5 + 5;
int n, q;
int a[TREE_N];//记录变量和节点的值
int st[N], p = 0;//数组模拟栈,p-栈顶指针
int cnt;//运算符编号
int tree[TREE_N][2];//模拟二叉树,存储变量编号
int what[TREE_N];//记录节点的类型,0-变量,1-&,2-|,3-!
int c[TREE_N];//记录节点的改变是否会改变整个表达式的值
int main() {
ios::sync_with_stdio(false);
string s;
getline(cin,s);
stringstream ss(s);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
int cnt = n;//运算符从n+1开始编号
while (getline(ss, s,' ')) {
if (s[0] == 'x') {//变量
st[++p] = stoi(s.substr(1));
}
else if (s[0] == '&') {
what[++cnt] = 1;
tree[cnt][1] = st[p--];
tree[cnt][0] = st[p--];
a[cnt] = a[tree[cnt][0]] && a[tree[cnt][1]];
st[++p] = cnt;
}
else if (s[0] == '|') {
what[++cnt] = 2;
tree[cnt][1] = st[p--];
tree[cnt][0] = st[p--];
a[cnt] = a[tree[cnt][0]] || a[tree[cnt][1]];
st[++p] = cnt;
}
else {
what[++cnt] = 3;
tree[cnt][0] = st[p--];
a[cnt] = !a[tree[cnt][0]];
st[++p] = cnt;
}
}
//如果节点i的改变会导致父节点发生改变,则c[i]=c[father[i]]
//这是一个自顶向下的过程
c[cnt] = 1;//此时cnt为最后一个运算符的编号+1代表了整个表达式,如果整个表达式结果节点改变则自然表达式结果改变
for (int i = cnt; i > n; i--) {
int l = tree[i][0], r = tree[i][1];
if (what[i] == 1) {
if (((!a[l]) && a[r]) != a[i])
c[l] = c[i];
if (((a[l]) && !a[r]) != a[i])
c[r] = c[i];
}
else if (what[i] == 2) {
if (((!a[l]) || a[r]) != a[i])
c[l] = c[i];
if (((a[l]) || !a[r]) != a[i])
c[r] = c[i];
}
else if (what[i] == 3) {
c[l] = c[i];//非一定会改变父节点的值
}
}
cin >> q;
for (int i = 0; i < q; i++) {
int k;
cin >> k;
cout << (a[cnt] ^ c[k]) << endl;
}
}
- 求和
颜色分组以及序号分组,因为只有奇数相加和偶数相加才能构成偶数(利用i%2),其次推导数学公式,简化计算!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 10007;
const int maxn = 1e5 + 5;
ll ans;
int n, m;
int x[maxn], c[maxn];
ll sum[maxn][2], s[maxn][2];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> x[i];
for (int i = 1; i <= n; i++) {
cin >> c[i];
s[c[i]][i % 2]++;
sum[c[i]][i % 2] = (sum[c[i]][i % 2] + x[i]) % MOD;//预先计算出x[i]之和
}
//找出颜色相同的两个点x,z,然后求其中间序号(x+z)/2&&(x+z)%2==0
for (int i = 1; i <= n; i++) {
ans = (ans + (ll)i * (x[i] * (s[c[i]][i % 2] - 2) + sum[c[i]][i % 2])) % MOD;
}
cout << ans;
}
- 在利用BFS进行搜索时,如果是求最短路,最终在到达终点时return即可,但是如果求得是最小代价,不能简单的return,需要比较到达时代价的大小,同时此时不需要vis数组,只需要在代价变小时将新的点加入队列同时更新代价数组即可。
- 贪心计算:对于a数组和s数组,选取x个数,如果最终的结果取决于选择的x个数的a值之和加上这x个数中最大的s值,采用贪心的想法:最终的结果要么是前x个最大的a值之和加上这x个数中最大的s,要么就是前x-1个最大的a值之和加上后面未取的(a+s)的最大值。代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
struct Node {
int s, a;
bool operator<(const Node& b)const {
return a > b.a;
}
}v[N];
int sum[N], q[N], h[N];//sum[i]表示前i项的a之和,q[i]表示前i项最大的s,h[i]表示i-N最大的疲劳值之和
//疲劳值分为往返走路疲劳值(最远距离的两倍)以及推销的疲劳值
//贪心体现在:最终对于x,要么是x个最大的a疲劳值加上其中的最大的s,要么是x-1个最大的疲劳值加上后面的一个最大的距离来弥补较小的a值
int n;
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> v[i].s;
for (int i = 1; i <= n; i++)
cin >> v[i].a;
sort(v + 1, v + 1 + n);//按照疲劳值排序
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + v[i].a;
q[i] = max(q[i - 1], 2 * v[i].s);
}
for (int i = n; i; i--)
h[i] = max(h[i + 1], 2 * v[i].s + v[i].a);
for (int i = 1; i <= n; i++)
cout << max(sum[i] + q[i], sum[i - 1] + h[i]) << endl;
}
- 当数据范围超出数组下标范围时,尝试使用路径压缩。
- 判断字符串是否是只经过排序后的字符串:两者同时sort,然后比较是否相同。
- 求最大公约数和最小公倍数
int gcd(int a,int b){
int r=0;
if(a<b) swap(a,b);
while(b!=0){
r=a%b;
a=b;
b=r;
}
return a;
}
最大公约数:a*b/gcd(a,b)