目录
栗酱的连通图
题目描述
萌萌哒栗酱有n个点,第i个点有点权ai(ai为偶数),你可以在任意两点之间添加一条边,每一条边的边权为连接它的两个点的点权之和除以2。
现在她需要添加n-1条边,使任意两点相互连通,并且连通后的边权和最大。
输入描述:
扫描二维码关注公众号,回复: 14484704 查看本文章![]()
第一行一个数T,表示有T组数据。
对于每组数据,第一行输入一个数n,表示点的数量,
接下来一行输入n个数,a1,a2,…,an,其中ai表示第i个点的点权。
任意两个相邻数之间用空格隔开。
输出描述:
对于每一组数据,输出一个数,即最大边权和。
示例1
输入
2
5
4 2 4 4 2
10
10 2 6 4 6 8 10 8 2 10
输出
14
73
备注:
T≤10
1≤n≤103
1≤ai≤103,保证ai为偶数。
源代码
//本题看似连通图的算法,实际非常简单,简单的排序
//因为联通的点可以是任意的,我们只需要将所有的点(除最大值的点)与最大值联通
//累计计算边权和即可
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000000 + 10;
int q[N];
void sort(int q[],int l,int r)
{
if(l >= r)return;
int x = q[l + r >> 1],i = l - 1,j = r + 1;
while(i < j)
{
do i ++ ;while(q[i] < x);
do j -- ;while(q[j] > x);
if(i < j)swap(q[i],q[j]);
}
sort(q,l,j);
sort(q,j + 1,r);
}
int main()
{
int t;
cin >> t;
while(t -- )
{
memset(q,0,sizeof(q));
int n;
cin >> n;
for(int i = 1;i <= n;i ++ )cin >> q[i];
sort(q,1,n);
int ans = 0;
for(int i = 1;i < n;i ++ )
{
ans += (q[i] + q[n]) / 2;
}
cout << ans << endl;
}
}
小杰的签到题
题目描述
小杰组织了一场比赛,在比赛前需要安排队伍签到,但他不确定签到要花多久时间,现在他来请求你的帮助。已知签到是在一个体育馆,该体育馆布置有三个桌子以供不同队伍的队伍同时签到,一个桌子最多只能有一支队伍签到,一支队伍只需在一张桌子前完成签到即可。如果三个桌子都有队伍在签到,其它需要签到的队伍就需要在任意一个桌子前排队,等待签到。
我们假设在t=0的时刻开始接受签到,n支队伍分别在a1,a2,...,an时刻到达体育馆,每支队伍完成签到均需b的时间,为使问题简单,我们忽略体育馆中移动的时间。你需要告诉小杰最早什么时刻,所有的队伍均签到完成。
输入描述:
多组读入。 输入数据的第一行是一个整数T,表示数据的组数。 每组数据的第一行是一个整数n,表示签到的队伍数。 接下来一行有n个整数ai,表示第i支队抵达体育馆的时间。 每组的最后一行是一个整数b,表示一支队伍完成签到的时间。
输出描述:
对于每组数据,输出最后一支队伍最早签到完成的时刻。
示例1
输入
2
5
1 2 4 5 7
4
7
4 4 4 2 8 9 11
5
输出
11
17
备注:
1≤n≤600
0≤ai≤104
1≤b≤1500
数据不超过250组
源代码
//双端队列,三人一队,在每次进行入队之前若是队列已经满了,则进行判断
//若需要等待则推入队伍到达的时间加上等待的时间,若无需等待直接推入队伍的到达时间即可
//队列满了就队头加一,从而保证队列当中一直处于一个递增的趋势
//也就是单调队列,队列的最后一队即为其到达可以开始的时间,也就是最后一队
//队尾元素加上每队需要等待的时间即为这些队伍所用的最短时间
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000000 + 10;
int a[N],q[N];
void sort(int q[],int l,int r)
{
if(l >= r)return;
int x = q[l + r >> 1],i = l - 1,j = r + 1;
while(i < j)
{
do i ++ ;while(q[i] < x);
do j -- ;while(q[j] > x);
if(i < j)swap(q[i],q[j]);
}
sort(q,l,j);
sort(q,j + 1,r);
}
int main()
{
int t;
cin >> t;
while(t -- )
{
memset(a,0,sizeof(a));
memset(q,0,sizeof(q));
int n;
cin >> n;
for(int i = 1;i <= n;i ++ )cin >> a[i];
sort(a,1,n);
int m;
cin >> m;
int hh = 0,tt = -1;
for(int i = 1;i <= n;i ++ )
{
if(tt - hh == 2)
{
if(a[i] >= q[hh] + m)q[++ tt] = a[i];
else q[++ tt] = q[hh] + m;
hh ++ ;
}
else q[++ tt] = a[i];
}
cout << q[tt] + m << endl;
}
return 0;
}
过来站站队伍
题目描述
在某个星球,每个人身上都有不一样的标号。一天,小娟在食堂排队时,发现后面老是喜欢插队,她看到很生气,拿出一张魔法卡,巴拉巴拉能量(魔仙变身,看多了动画片,hhh)。。。。。。。,将他们全部按照从小到大按照标号排好了。你能帮忙写出魔法卡内部的程序吗?写出来就给你一个气球。嘿嘿嘿
输入描述:
第一行,输入一个整数n(1<=n<=100000); 第二行,输出n个整数; 注意多组输入
输出描述:
输出n个数
示例1
输入
3
1 3 2
输出
1 2 3
示例2
输入
5
1 3 4 2 5
输出
1 2 3 4 5
源代码
#include <iostream>
using namespace std;
const int N = 1000000 + 10;
int q[N];
void sort(int q[],int l,int r)
{
if(l >= r)return;
int x = q[l + r >> 1],i = l - 1,j = r + 1;
while(i < j)
{
do i ++ ;while(q[i] < x);
do j -- ;while(q[j] > x);
if(i < j)swap(q[i],q[j]);
}
sort(q,l,j);
sort(q,j + 1,r);
}
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++ )cin >> q[i];
sort(q,1,n);
for(int i = 1;i <= n;i ++ )cout << q[i] << ' ';
return 0;
}
一堆点
题目描述
这个问题很简单,有n个三维点(x,y,z),要求按照它们距离原点的距离来排序,若距离相等,则按照x的顺序递增,若x也相等,则按照y递增的顺序递增(依次类推,不会输入重复点)
输入描述:
第一行输入一个正整数n(1<=n<=106),表示有n个三维点
随后n行,每行包含3个实数x,y,z表示一个点的坐标(均在double类型内)。
输出描述:
按照排序之后的结果,每行输出一个三维点的x y z方向的坐标,两个数之间以一个空格分隔
示例1
输入
4
0 0 0
1 1 1
3 3 3
-2 -2 -2
输出
0 0 0
1 1 1
-2 -2 -2
3 3 3
源代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Point
{
double x;
double y;
double z;
double d;
};
int cmp(const struct Point &A,const struct Point &B)
{
if(A.d != B.d)return A.d < B.d;
else if(A.x != B.x)return A.x < B.x;
else if(A.y != B.y)return A.y < B.y;
else return A.z < B.z;
}
vector<Point> a;
int main()
{
int n;
cin >> n;
while(n -- )
{
Point t;
cin >> t.x >> t.y >> t.z;
t.d = t.x * t.x + t.y * t.y + t.z * t.z;
a.push_back(t);
}
sort(a.begin(),a.end(),cmp);
for(int i = 0;i < int(a.size());i ++ )cout << a[i].x << ' ' << a[i].y << ' ' << a[i].z << endl;
return 0;
}
别看了 这是水题
题目描述
把一个长度为N的数值数组按从小到大的顺序排序并输出
输入描述:
输入为两行 第一行为一个整型数字N 第二行输入N个整型数字num 代表数组里面的元素(每个元素之间用空格隔开)
输出描述:
输出为一行 即为数组从小到大排序后的结果 每个数字之间用空格隔开(行末没有空格)
示例1
输入
5 2 8 7 4 5
输出
2 4 5 7 8
示例2
输入
4 2 2 2 2
输出
2 2 2 2
备注:
0<N<1000 0<num<=10000
源代码
#include <iostream>
using namespace std;
const int N = 1000000 + 10;
int q[N];
void sort(int q[],int l,int r)
{
if(l >= r)return;
int x = q[l + r >> 1],i = l - 1,j = r + 1;
while(i < j)
{
do i ++ ;while(q[i] < x);
do j -- ;while(q[j] > x);
if(i < j)swap(q[i],q[j]);
}
sort(q,l,j);
sort(q,j + 1,r);
}
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++ )cin >> q[i];
sort(q,1,n);
for(int i = 1;i <= n;i ++ )cout << q[i] << ' ';
return 0;
}
兔子的逆序对
题目描述
兔子最近喜欢上了逆序对。
一个逆序对(i,j) 需要满足 i < j 且 ai > aj
兔子觉得只是求一个序列的逆序对个数太没有意思了。
于是兔子想到了一个更有趣的问题!
兔子可以把区间[L,R] 反转,例如序列{1,2,3,4} 反转区间[1,3] 后是{3,2,1,4}。
兔子有m次反转操作,现在兔子想知道每次反转后逆序对个数是奇数还是偶数,兔子喜欢偶数,而讨厌奇数。
请注意,每一次反转操作都会对原序列进行改变。例如序列{1,2,3,4} 第一次操作区间[1,2] 后变成{2,1,3,4} 第二次反转区间[3,4] 后变成 {2,1,4,3}
输入描述:
第一行一个整数 n,表示序列的大小。 第二行 n 个整数ai 表示序列的各个元素。 第三行一个整数m,表示操作个数。 接下来 m 行,每行两个整数 l,r,表示反转的区间。
输出描述:
输出共m行每行一个字符串,表示反转后序列逆序对个数的奇偶性,如果是逆序对个数奇数,输出"dislike"(不含引号),如果是偶数,输出"like"。
示例1
输入
4
1 2 3 4
4
1 2
3 4
1 4
2 3
输出
dislike
like
like
dislike
说明
注意:以下的(i,j)指的是位置 i 和位置 j a={2,1,3,4} 的逆序对是 (1,2) 共1个,1是奇数,所以是dislike a={2,1,4,3} 的逆序对是 (1,2) (3,4)共2个,2是偶数,所以是like a={3,4,1,2} 的逆序对是 (1,3) (1,4) (2,3) (2,4)共4个,4是偶数,所以是like a={3,1,4,2} 的逆序对是 (1,2) (1,4) (3,4) 共3个,3是奇数,所以是dislike
备注:
对于20%的数据 1 ≤ n ≤ 100 1 ≤ m ≤ 10 对于40%的数据 1 ≤ n ≤ 2000 1 ≤ m ≤ 50 对于60%的数据 1 ≤ n ≤ 2000 1 ≤ m ≤ 104 对于100%的数据 1 ≤ n ≤ 105 1 ≤ m ≤ 2*106
对于所有数据 l ≤ r且 ai 是n的一个排列,即ai互不相同且ai ≤ n
由于读入数据较大,建议使用快速读入。
源代码
//本题我没有使用快读也过了,肯定使用快读之后速度会更加快
//基础思想在于基于分治的归并排序,逆序对的计算公式为ans = mid - i + 1
//分治即为不同二分元素,直至分至一个元素时结束
//在每次分的两个区间当中,若前一区间存在着大于后一区间的数
//由于在分治的同时也排序,因此每个区间的数都是升序的
//若是第一区间开头的某个数大于第二区间的数,也就意味着在第一区间当中该数后面的所有数都可以构成逆序对
//这也就是逆序对计算公式的又来
//在刚开始的时候,我们求取逆序队的个数,用于以后处理来累加逆序对个数
//观察规律我们可以发现逆序对个数的规律,就拿样例来说
//初始 0
//第一次 1 (1,2) 1
//第二次 2 (3,4) 1
//第三次 4 (1,4) 2
//第四次 3 (2,3) -1
#include <iostream>
using namespace std;
const int N = 2000000 + 10;
int q[N],tep[N],ans = 0;
void merge_sort(int q[],int l,int r)
{
if(l >= r)return;
int mid = l + r >> 1;
merge_sort(q,l,mid);
merge_sort(q,mid + 1,r);
int i = l,j = mid + 1,k = 0;
while(i <= mid && j <= r)
{
if(q[i] <= q[j])tep[k ++ ] = q[i ++ ];
else
{
tep[k ++ ] = q[j ++ ];
ans += mid - i + 1;
}
}
while(i <= mid)tep[k ++ ] = q[i ++ ];
while(j <= r)tep[k ++ ] = q[j ++ ];
for(int i = l,j = 0;i <= r;i ++ ,j ++ )q[i] = tep[j];
}
int main()
{
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++ )cin >> q[i];
int m;
scanf("%d",&m);
merge_sort(q,1,n);
while(m -- )
{
int l,r;
scanf("%d%d",&l,&r);
ans += (r - l + 1) / 2;
if(ans & 1)printf("dislike\n");
else printf("like\n");
}
return 0;
}
留下一道[归并排序][树状数组][线段树]未补点我来补