[第五场]爆炸记

T1

题目描述

渔夫sime昨晚抓住了N条金枪鱼。在一个特殊的app的帮助下,他将它们卖给一家专门收购优质鱼的日本著名公司。app是以何种方式估算金枪鱼的价值的呢? 根据金枪鱼的照片,app返回两个估计价值,P1和P2。如果两个估值之间的差异小于或等于X,则采用更高的那个估值。如果差值大于X,则app返回第三个估计价值P3,然后将该估值作为金枪鱼的最终价值。 编写一个程序,根据app给这每条金枪鱼的估值(有时两个,有时三个),计算捕获的金枪鱼的总价值。

输入格式

第一行输入包含整数N(1≤N≤20)。表示金枪鱼的数量。

第二行输入包含整数X(1≤X≤10)。表示题目中提到的判断标准中的X。

接下来N组数,每组属于以下两种情况之一:

●在第一行中包含两个整数P1和P2(1≤P1,P2≤100)

●在第一行中包含两个整数P1和P2(1≤P1,P2≤100),在第二行中包含一个整数P3(1≤P3≤100)

其中P1、P2、P3为题目中提到的估值。

输出格式

输出一个整数。表示所有金枪鱼的总价。

样例

样例输入1

5
2
3 4
2 1
5 3
4 4
4 2

样例输出1

19

样例输入2

4
2
3 5
2 8
4
6 5
6 3
7

样例输出2

22

样例输入3

3
10
20 50
30
20 40
50
70 20
10

样例输出3

90

数据范围与提示

无特殊分数分布。

解题思路

按题意输入输出即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n,ans,x;
char c;
int main(){
	//freopen("tuna.in","r",stdin);
	//freopen("tuna.out","w",stdout);
	scanf ("%d",&n);
	scanf ("%d",&x);
	for (int i = 1;i <= n;i ++){
		int p1,p2,p3;
		scanf ("%d",&p1);
		scanf ("%c",&c);
		if (c == '
'){
			i --;
			continue;
		}
		else 
			scanf ("%d",&p2);
		if (abs(p1 - p2) <= x)
			ans += max(p1,p2);
		else {
			scanf ("%d",&p3);
			ans += p3;
		}
	}
	printf("%d
",ans);
}

T2

题目描述

Pareto法则,也被称为“80/20法则”,它指出在许多情况下,80%的结果来自20%的(最重要的)原因。例如,微软发现,通过修复20%最常见的报告错误,他们可以消除80%的系统停机时间。在商界,人们常说80%的收入来自20%最重要的客户。在移动游戏领域,当涉及到具有免费基本功能的游戏时,50%的利润来自于0.5%的玩家。有人说80%的成功将来自于20%的行动。

众所周知,世界上80%的财宝是由20%最富有的人拥有的。你的任务是根据一家银行的所有客户的银行账户来检查这一规则的有效性。20%的账户持有总金额的80%是真的吗?是否有一个更强力的的主张,例如,10%的账户持有85%的总金额?

更准确地说:根据N个客户的账户余额,您的任务是找到最大差异的数字A和B使得B-A的值最大,这里的B和A定义如下:恰好有A%的客户持有银行所有客户总余额的B%。

输入格式

第一行输入包含一个整数N(1≤N≤3*1e5)。表示银行的客户的数量。

第二行输入包含了N个整数Ci(0≤Ci≤3*1e8)。第i个整数Ci表示第i个客户的账户余额。

输出格式

输出两行,第一行输出一个实数A,第二行输出一个实数B。表示A%的客户持有%B的总余额且B-A最大。数据保证这样的方案只有一种。如果你的答案和标准答案的误差不超过0.01那么你的答案被视为正确的。

样例

样例输入1

2
100 200

样例输出1

50.0
66.66666666666666

样例输入2

8
100100 10 100 1000 1 10100 90100 100100

样例输出2

37.5
96.28172769816027

数据范围与提示

无特殊分数分布。

解题思路

van一下,我们从大到小排个序,然后枚举即可。这样肯定最大。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n;
long long c[300005],sum,sum1;
double a,b,ans;
bool cmp(long long a,long long b){
	return a > b;
}
int main(){
	//freopen("pareto.in","r",stdin);
	//freopen("pareto.out","w",stdout);
	scanf("%d",&n);
	for (int i = 1;i <= n;i ++){
		scanf ("%lld",&c[i]);
		sum += c[i];
	}
	sort(c + 1,c + 1 + n,cmp);
	for (int i = 1;i <= n;i ++){
		sum1 += c[i];
		double s1 = sum1 * 1.0 / sum * 100;
		double s2 = i * 1.0 / n * 100;
		if (s1 - s2 > a - b){
			a = s1,b = s2;
		}
	}
	printf("%lf
%lf",b,a);
}

T3

有N个矩形,它们以二维直角坐标系的原点为中心,它们的边与坐标轴平行。每个矩形都以其宽度(沿X轴方向)和高度(沿Y轴方向)进行唯一标识。下图描述了第一个样例。

avatar

Mirko给每个矩形都涂上了某种颜色,现在想知道纸上有颜色部分的面积。换句话说,他想知道至少属于一个矩形的小方格的数目。

输入格式

第一行输入包含一个整数N(1≤N≤1e6)。表示矩形的个数。 接下来N行每行包含两个偶数X和Y(2≤x,y≤1e7)。表示第i个矩形的宽度和高度。

输出格式

输出一个整数。表示有颜色部分的面积。

样例

样例输入1

3
8 2
4 4
2 6

样例输出1

28

样例输入2

5
2 10
4 4
2 2
8 8
6 6

样例输出2

68

数据范围与提示

对于40%的数据,输入的所有数字都小于3333。 对于50%的数据,没有一个矩形严格位于另一个矩形内。

解题思路

很明显,算出一个象限然后乘4比较好。

我们要处理答案,肯定要特殊排序,按x的从大到小或按y的从大到小都可以。

我们再保存另一个乱序的x,y的max值。这样一点一点计算面积。

不好描述,可以画一下图或结合一下代码理解。

还有一点要开long long 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
struct node{
	long long x,y;
	bool operator < (const node &a)const {
		return y > a.y;
	}
}s[1000005];
int n,maxl;
long long ans;
int read(){
	int f = 1,x = 0;
	char s = getchar();
	while (s < '0' || s > '9'){
		if (s == '-')
			f = -1;
		s = getchar();
	}
	while (s >= '0' && s <= '9'){
		x = x * 10 + s - '0';
		s = getchar();
	}
	return x * f;
}
int main(){
	//freopen("unija.in","r",stdin);
	//freopen("unija.out","w",stdout);
	n = read();
	for (int i = 1;i <= n;i ++){
		s[i].x = read();
		s[i].y = read();
		s[i].x /= 2;
		s[i].y /= 2;
	}
	sort(s + 1,s + 1 + n);
	maxl = s[1].x;
	ans += s[1].x * s[1].y;
	for (int i = 2;i <= n;i ++){
		if (s[i].x <= maxl)
			continue;
		else {
			ans += 1ll * (s[i].x - maxl) * s[i].y;
			maxl = s[i].x;
		}
	}
	printf("%lld
",ans * 4);
}

T4

题目描述

一个国家有n个城市,城市之间连接着双向航空线路。一位疯狂的航空公司总裁Ronald Krump经常改变航班时刻表。更准确地说,他每天都做以下事情:

●选择其中一个城市

●如果该城市和某个其他城市之间之前没有航线那么在这两个城市之间创建一条航线,如果该城市和某个其他城市之间之前已有航线那么取消这条航线

例如,如果从城市5有航线通往城市1和2,但没有航线通往城市3和4,那么在Krump选择城市5并进行操作后,将有从城市5通往城市3和4的航线,但没有从城市5通往城市1和2的航线。

这个国家的公民在想,是否有一天航线图会变为完全图。换言之,当天任意两个不同的城市之间存在一条航线(直达)。写一个程序,根据当前的航线图,确定是否有可能有某一天出现这种情况,通过Krump的操作。

输入格式

第一行输入包含一个整数N(2≤N≤1000)。表示城市的数量。城市从1到N编号。 第二行输入包含一个整数M(0≤M≤N*(N-1)/2)。表示当前航线的数量。 接下来M行每行包含两个不同的整数,表示一条航线连接的两个城市的编号。

输出格式

如果有一天航线图会变为完全图,那么输出“DA”。否则输出“NE”。输出均不含引号。

样例

样例输入1

2
0

样例输出1

DA

样例输入2

3
2
1 2
2 3

样例输出2

NE

样例输入3

4
2
1 3
2 4

样例输出3

DA

解题思路

结论题。考场骗分原地爆炸。

首先你要知道一些结论。

1.当原图是一个非完全图时,是不可能令它变成完全图。

证明:显然易证。

2.当原图是两个完全图时,一定可以令它变成完全图。

证明:可以先从一个完全图一个点推起,画一下图还是很容易看出来。

3.当原图是两个以上完全图时,一定不能令它变成完全图。

证明:我们首先考虑3个吧。由于2已经得证,我们尽量把这个转换为2,但是肯定转化不了的。因为你同时也与令一个完全图连了边。所以2个以上的都不可以做出。

4.高端操作:

我们都知道完全图需要n*(n - 1) / 2的边。这个边数减去原图中已有的边就等于两个连通图的点数乘积,至于为什么画一下图可以知道。因此,我们仅需dfs一下,就可以判断所有情况。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int cnt[1005],fa[1005];
int n,m,num[1005],cnt1,tot;
bool vis[1005],vis1[1005][1005];
vector <int>G[1005];
void dfs(int step){
	num[++ cnt1] = step;
	vis[step] = 1;
	for (int i = 0;i < G[step].size();i ++){
		if (!vis[G[step][i]]){
			vis[G[step][i]] = 1;
			dfs(G[step][i]);
			return ;
		}
	}
}
int main(){
	//freopen("ronald.in","r",stdin);
	//freopen("ronald.out","w",stdout);
	scanf ("%d",&n);
	scanf ("%d",&m);
	if (m == n * (n - 1) / 2){
		printf("DA
");
		return 0;
	}
	if (m == 0){
		if (n < 3)
			printf("DA
");
		else	
			printf("NE
");
		return 0;
	}
	for (int i = 1;i <= m;i ++){
		int a,b;
		scanf ("%d%d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a);
		vis1[a][b] = vis1[b][a] = 1;
	}
	dfs(1);
	for (int i = 1;i <= cnt1;i ++)
		for (int j = i + 1;j <= cnt1;j ++)
			if (vis1[num[i]][num[j]])
				tot++;
	int t1 = cnt1 * (cnt1 - 1) / 2;
	int t2 = n * (n - 1) / 2 - m;
	if (tot != t1 || (t2 / cnt1) != (n - cnt1))
		printf("NE
");
	else
		printf("DA
");
}

并查集

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int cnt[1005],fa[1005];
int n,m,num[1005],cnt1,tot,sum[1005];
bool vis[1005],vis1[1005][1005];
void makeset(int x){
	for (int i = 1;i <= x;i ++)
		fa[i] = i;
}
int findset(int x){
	if (fa[x] != x)
		fa[x] = findset(fa[x]);
	return fa[x];
}
int main(){
	//freopen("ronald.in","r",stdin);
	//freopen("ronald.out","w",stdout);
	scanf ("%d",&n);
	scanf ("%d",&m);
	if (m == n * (n - 1) / 2){
		printf("DA
");
		return 0;
	}
	if (m == 0){
		if (n < 3)
			printf("DA
");
		else	
			printf("NE
");
		return 0;
	}
	makeset(n);
	for (int i = 1;i <= m;i ++){
		int a,b;
		scanf ("%d%d",&a,&b);
		int t1 = findset(a);
		int t2 = findset(b);
		fa[t1] = t2;
		cnt[a] ++;
		cnt[b] ++;
	}
	for (int i = 1;i <= n;i ++){
		sum[findset(i)] ++;
		if (findset(i) == i){
			++ cnt1;
			num[cnt1] = i;
		}
	}
	if (cnt1 > 2){
		printf("NE
");
		return 0;
	}
	for (int i = 1;i <= cnt1;i ++){
		for (int j = 1;j <= n;j ++){
			if(fa[j] == num[cnt1])
				if (cnt[j] != sum[fa[j]] - 1){
					printf("NE
");
					return 0;
				}
		}
	}
	printf("DA
");
}

T5 

题目描述

Mirko是一个非常简单的人。Mirko的朋友Darko给了他由N个自然数组成的一个数组,并问了他Q个问题。每个问题由两个整数L和R组成,要求Mirko回答在数组的第L位到第R位中恰好出现两次的不同值有多少种。

输入格式

第一行输入包含整数N和Q(1≤N,Q≤5*1e5)。表示数组中自然数的个数和问题的个数。 第二行输入包含N个自然数ai(ai≤1e9)。表示数组。 接下来Q行每行包含两个整数Li和Ri(1≤Li≤Ri≤N),表示一个问题询问的区间。

输出格式

输出Q行,每行一个整数。第i行的整数表示第i个问题的答案。

样例

样例输入1

5 1
1 2 1 1 1
1 3

样例输出1

1

样例输入2

5 2
1 1 1 1 1
2 4
2 3

样例输出2

0
1

样例输入3

5 2
1 1 2 2 3
1 1
1 5

样例输出3

0
2

解题思路

查询很多,线段树估计要炸,我们选择莫队。

话说莫队是啥,相信会有人认为是提莫队长...

戳我看莫队

点击下载《NOI》

不捞了...

还是给个通俗易懂的莫队博客

a很大,但数量较少,我们选择离散化。

一切的一切考试都想到了,当时觉得这分数稳稳的。

结果

当时很绝望...认为可能有什么玄学操作。

结果发现...自己莫队一直都有问题...

老师本来是讲过分块思想的,然而自己并没有在代码中实现,还过了两道水题。当时觉得莫队挺暴力的,很震惊。但心里美滋滋。

测数据有点虚...大数据跳不出...

结果这里原地爆炸。

分块思想可以说是莫队算法的精髓。我们将原访问分成几个分块,一个一个从左到右解决。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int unit;
struct node{
	int l,r,pos;
	bool operator < (const node &x)const{
		if (x.l / unit == l / unit)
			return r < x.r;
		else 
			return l < x.l;
        //return l < x.l; f**k
	}
}s[500005];
struct node1 {
	int x,num;
	bool operator < (const node1 &a)const{
		return x < a.x;
	}
}b[500005];
int n,q,a[500005],curl = 1,curr,ans;
int ans1[500005],cnt[500005],num[500005],tot;
int read(){
	int f = 1,x = 0;
	char s = getchar();
	while (s < '0' || s > '9'){
		if (s == '-')
			f = -1;
		s = getchar();
	}
	while (s >= '0' && s <= '9'){
		x = x * 10 + s - '0';
		s = getchar();
	}
	return x * f;
}
void remove(int step){
	if (cnt[num[step]] == 2)
		ans --;
	cnt[num[step]] --;
	if (cnt[num[step]] == 2)
		ans ++;
}
void add(int step){
	if (cnt[num[step]] == 2)
		ans --;
	cnt[num[step]] ++;
	if (cnt[num[step]]== 2)
		ans ++;
}
int main(){
	//freopen("poklon.in","r",stdin);
	//freopen("poklon.out","w",stdout);
	n = read(),q = read();
	unit = int(sqrt(n));
	for (int i = 1;i <= n;i ++){
		a[i] = read();
		b[i].x = a[i];
		b[i].num = i;
	}
	sort(b + 1,b + 1 + n);
	for (int i = 1;i <= n ;i ++){
		if (b[i].x != b[i - 1].x)
			num[b[i].num] = ++ tot;
		else 
			num[b[i].num] = tot;
	}
	for (int i = 1;i <= q;i ++){
		s[i].l = read();
		s[i].r = read();
		s[i].pos = i;
	}
	sort(s + 1,s + 1 + q);
	for (int i = 1;i <= q;i ++){
		while (curl < s[i].l)
			remove(curl ++);
		while (curl > s[i].l)
			add(-- curl);
		while (curr < s[i].r)
			add(++ curr);
		while (curr > s[i].r)
			remove(curr --);
		ans1[s[i].pos] = ans;
	}
	for (int i = 1;i <= q;i ++)
		printf("%d
",ans1[i]);
}

PJW与我旁边的DY还幸灾乐祸。

这次考试含精量挺低的,然而就没考好

原文地址:https://www.cnblogs.com/lover-fucker/p/13566668.html