额因为最近改题速度有点慢,所以总结出得很晚,但都会陆续补齐的。
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还是很简单的只要多细心点。