2019.8.2 JZ DAY2总结

额因为最近改题速度有点慢,所以总结出得很晚,但都会陆续补齐的。

T 1 T1 T1
A t t a c k Attack Attack

Description
chnlich 非常喜欢玩三国志这款游戏,并喜欢用一些策略出奇制胜。现在,他要开始征服世界的旅途了。他的敌人有N 座城市和N 个太守, N个城市可以看作在二维平面上的N 个点。N 座城市的标号为0,1,2,…,N-1。第i 座城市的坐标为(Xi,Yi),镇守这座城市的太守的能力值为Zi。
chnlich 每次会选择一个边平行于坐标轴的矩形区域,并奇袭其中太守能力值第K小的城市(奇袭结束之后城市与太守依然存在)。
不过,他的敌人经常会偷偷交换两座城市的太守,防止弱点被chnlich 发现。
现在,chnlich 想要知道,每次奇袭时他的敌人的能力值。

Input
输入的第一行包含两个整数 N,M,N 表示城市与太守的个数,M 表示接下来发生了 M 个事件。
输入的第二行到第 N+1行,每行包含三个整数,第 i+2行的三个整数依次表示编号为 i 的城市的 Xi,Yi,Zi,含义如题所述。
输入的第 N+2行到第 N+M+1行,每行有两种可能形式:
第一种
QUERY x0 y0 x1 y1 k
表示 chnlich 询问一个相对顶点为(x0,y0),(x1,y1)的矩形中,第 k 小能力值太
守的能力值。
第二种
SWAP x y
表示 chnlich 的敌人交换了编号为 x 和 y 两座城市的太守。

Output
对于每一个 QUERY,输出一行。
若不存在第 k 小能力值的太守,输出"It doesn’t exist."(不包含引号)。
否则输出一个整数,表示矩形内能力值第 k 小太守的能力值。

Sample Input
3 5
1 1 1
2 2 2
3 3 3
QUERY 1 1 3 3 3
SWAP 0 1
QUERY 2 2 4 4 1
SWAP 2 2
QUERY 2 2 3 3 3

Sample Output
3
1
It doesn’t exist.
Data Constraint

Hint
对于100%的数据,N<=60000,M<=10000,0<=Xi,Yi,Zi<=109,k<=109,保证所有操作均合法。

考场打了一个十分不优美的暴力,加上审题有误只有9.5分。就是我是每次快排,这样子的话时间复杂度会变得异常大,但是如果我事先快排好再进行solve的话就可以拿到100pts的好成绩。

#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 6e4 + 10;
struct Node{
	int x,y,z,id;
} f[N];
int n,m,g[N];
char ch[10];

bool cmp(Node a,Node b) {return a.z < b.z;}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i = 0; i < n; i ++)
		scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z),f[i].id = i;
	sort(f,f + n,cmp);
	for (int i = 0; i < n; i ++) g[f[i].id] = i;
	while (m --)
	{
		scanf("%s ",ch);
		if (ch[0] == 'Q')
		{
			int x1,x2,y1,y2,k,cnt = 0;
			scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
			if (x1 > x2) swap(x1,x2);
			if (y1 > y2) swap(y1,y2);
			for (int i = 0; i < n; i ++)
			{
				if (f[i].x >= x1 && f[i].x <= x2 && f[i].y >= y1 && f[i].y <= y2) cnt ++;
				if (cnt == k) {printf("%d\n",f[i].z);break;}
			}
			if (k > cnt) printf("It doesn't exist.\n"); 
		} else 
		{
			int a,b;
			scanf("%d%d",&a,&b);
			if (a == b) continue;
			swap(f[g[a]].x,f[g[b]].x);
			swap(f[g[a]].y,f[g[b]].y);
			swap(g[a],g[b]);
		}
	}
	return 0;
}

T 2 T2 T2
C o n t r a Contra Contra

Description
偶然间,chnlich 发现了他小时候玩过的一个游戏“魂斗罗”,于是决定怀旧。但是这是一个奇怪的魂斗罗 MOD。
有 N 个关卡,初始有 Q 条命。
每通过一个关卡,会得到 u 分和1条命,生命上限为 Q。其中 u=min(最近一次连续通过的关数,R)。
若没有通过这个关卡,将会失去1条命,并进入下一个关卡。
当没有生命或没有未挑战过的关卡时,游戏结束,得到的分数为每关得到的分数的总和。
由于 chnlich 好久不玩这个游戏了,每条命通过每个关卡的概率均为p(0<=p<=1),原先 chnlich 的最高分纪录是 S。
现在 chnlich 想要知道,当 p 至少为多少时,chnlich 期望获得的总分数能够超过原先的最高分。

Input
输入共一行,分别表示整数 N,整数 R,整数 Q,原先的最高分整数 S。

Output
输出共一行,若不存在这样的 p,输出"Impossible."(不包含引号),否则输出 p(保留6位小数)。

Sample Input
【样例输入一】
4 2 1 5

【样例输入二】
12 3 2 12

Sample Output
【样例输出一】
0.880606

【样例输出二】
0.687201

Hint
【数据说明】
对于20%的数据,N<=15
对于50%的数据,N<=10000
对于100%的数据,N<=10^8,1<=R<=20,1<=Q<=5,保证 S 是一个可能出现的分数。

【补充说明】
例如,当 N=12,R=3,Q=2时
第一关:未通过 u=0 获得分数0 总分为0 剩余生命1
第二关:通过 获得分数1 总分为1 剩余生命2
第三关:通过 获得分数2 总分为3 剩余生命2
第四关:通过 获得分数3 总分为6 剩余生命2
第五关:通过 获得分数3 总分为9 剩余生命2
第六关:未通过 获得分数0 总分为9 剩余生命1
第七关:通过 获得分数1 总分为10 剩余生命2
第八关:未通过 获得分数0 总分为10 剩余生命1
第九关:未通过 获得分数0 总分为10 剩余生命0
游戏结束 总分为10
这是 chnlich 游戏的一种可能性

本来这什么跟什么啊,乱七八糟,感觉题目都看的我一脸懵逼。
不过用dfs暴力求求期望得了20分。正解是dp。

#include <cstdio>
using namespace std;

const int N = 100;
int n,r,q,s,L,R,t,p[30][10];
double ans,a[N][N],b[N][N],c[N][N];

int min(int a,int b) {return a < b ? a : b;}

int max(int a,int b) {return a > b ? a : b;}

bool check(int k)
{
	int cnt = 0;
	double P = k / 1000000000.000000;
	for (int i = 0; i <= q; i ++)
	{
		int kk = (i == q) ? r : min(i-1, r);
		kk = max(kk,0);
		for (int j = 0; j <= kk; j ++)
			p[i][j] = ++ cnt;
	}
	a[1][1] = 1;
	for (int i = 1; i <= q; i ++)
	{
		int kk = (i == q) ? r : min(i-1, r);
		kk = max(kk,0);
		for (int j = 0; j <= kk; j ++)
		{
			int x = p[i][j],y = p[i - 1][0],z = p[min(i + 1,q)][min(j + 1,r)];
			if (i > 1) a[x][y] = (1 - P);
			a[x][z] = P;
			a[x][1] = P * min(j + 1,r);
		}
	}
	for (int i = 1; i <= cnt; i ++) b[i][i] = 1;
	int y = n;
	while (y)
	{
		if (y & 1)
		{
			for (int i = 1; i <= cnt; i ++)
				for (int j = 1; j <= cnt; j ++)
					for (int k = 1; k <= cnt; k ++)
						c[i][j] += b[i][k] * a[k][j];
			for (int i = 1; i <= cnt; i ++)
				for (int j = 1; j <= cnt; j ++)
						b[i][j] = c[i][j],c[i][j] = 0;
		}
		for (int i = 1; i <= cnt; i ++)
				for (int j = 1; j <= cnt; j ++)
					for (int k = 1; k <= cnt; k ++)
						c[i][j] += a[i][k] * a[k][j];
			for (int i = 1; i <= cnt; i ++)
				for (int j = 1; j <= cnt; j ++)
						a[i][j] = c[i][j],c[i][j] = 0;
		y >>= 1;
	}
	bool pt = 0;
	if (b[p[q][0]][1] > s) pt = 1; 
	for (int i = 1; i <= cnt; i ++)
		for(int j = 1; j <= cnt; j ++) a[i][j] = b[i][j] = 0;
	return pt;
}

int main()
{
	scanf("%d%d%d%d",&n,&r,&q,&s);
	L = 0,R = 1000000000;
	if (!check(1000000000))
	{
		printf("Impossible.");
		return 0;
	}
	while (L < R)
	{
		int mid = (L + R) >> 1;
		if (check(mid)) ans = (double)mid / 1000000000.000000,R = mid - 1; else L = mid  + 1;
	}
	printf("%.6lf",ans);
	return 0;
}

T 3 T3 T3
B o m b Bomb Bomb

Description
A 国和 B 国是两个超级大国,长期处于冷战状态;
A 国在 B 国中设有 N 个情报站,编号为 1,2,3, …… ,N ,每个情报站有一个坐标 (Xi,Yi) 。但是, A 国的工作人员发现,每个情报站里都被埋上了炸弹!
这些炸弹非常特殊 , 只要同时拆除其中的三个炸弹 , 所有炸弹就都不会爆炸了。
由于各个情报站联络需要代价 , 拆除炸弹需要花费的总代价为这些炸弹两两之间的曼哈顿距离和。
现在 A 国的指挥部门找到了你 , 希望知道可能需要的最大代价和最小代价 。

Input
输入的第一行包含一个整数 N 。接下来 N 行,第 i+1 行两个整数 Xi,Yi ,表示第 i 个情报站的坐标。

Output
输出两行 , 每行包含一个整数 , 第一行表示可能的最大代价 , 第二行表示可能的最小代价。

Sample Input
4
1 1
1 2
2 1
2 3

Sample Output
6
4

Data Constraint
Hint
对于 30% 的数据, N<=500
对于另外 10% 的数据,每个点出现至少两遍
对于 50% 的数据, N<=1000
对于 60% 的数据, N<=8000
对于 70% 的数据, N<=15000
对于 80% 的数据, N<=50000
对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8

【 注释 】
对于两个点 (X0,Y0),(X1,Y1) ,
它们之间的曼哈顿距离为 abs(X0-X1)+abs(Y0-Y1) 。

至今没A,不过因为人品还过意的去拿到了50pts,就姑且附上暴力代码趴。

#include <cstdio>
#include <cmath>
using namespace std;

const int N = 1e5 + 10;
int n,x[N],y[N],max,min = 1e9 + 10;

int read()
{
	int x = 0,w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') w = -1;ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
	return x * w;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i ++)
		x[i] = read(),y[i] = read();
	for (int i = 1; i <= n; i ++)
		for (int j = i + 1; j <= n; j ++)
			for (int k = j + 1; k <= n; k ++)
			{
				int s = abs(x[i] - x[j]) + abs(y[i] - y[j]) + abs(x[j] - x[k]) + abs(y[j] - y[k]) + abs(x[k] - x[i]) + abs(y[k] - y[i]);
				if (s > max) max = s;
				if (s < min) min = s; 
			}
	printf("%d\n%d",max,min);
	return 0;
}

分数虽然只有74.5,不过排名还算客观。唉,感觉这套题拿个170还是很简单的只要多细心点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值