Codeforces Round #614 (Div. 2)
A. ConneR and the A.R.C. Markland-N (CF 1293 A)
题目大意
\(n\)层楼,每层都有个餐厅,但有\(k\)个餐厅不开放,分别在\(a_i\)层,\(Colin\ "ConneR"\ Neumann\ Jr\)在第\(s\)层,现在他要去吃午饭,问他去餐厅最小的跨楼层是多少?
解题思路
\(n\)巨大但\(k\)很小,用\(set\)储存\(a_i\),拿两个指针从\(s\)往上往下扫到没有关闭的餐厅的即可。
神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
int main(void) {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int kase; cin>>kase;
for (int i = 1; i <= kase; i++) {
int n,s,k;
cin>>n>>s>>k;
set<int> qwq;
for(int u,i=1;i<=k;++i){
cin>>u;
qwq.insert(u);
}
int l=s;
int r=s;
while(true){
if (l>=1) if (qwq.find(l)!=qwq.end()) --l; else break;
if (r<=n) if (qwq.find(r)!=qwq.end()) ++r; else break;
}
int ans=0;
if (l==0) ans=r-s;
else if (r==n+1) ans=s-l;
else ans=min(s-l,r-s);
cout<<ans<<endl;
}
return 0;
}
B. JOE is on TV! (CF 1293 B)
题目大意
初始\(n\)个对手,答题,答错出局,某个回合,还有\(s\)个对手,若该回合有\(t\)个对手答错,则你可以获得\(\dfrac{t}{s}美元\)。问你可能获得的最大美元数是多少?
解题思路
经过数次枚举我们可以猜想每次一个人答错,最终获得的美元数最多,以下为证明:
设当前有\(t\)位选手,若当前回有\(s(s > 1)\)位选手答错,则获得的美元为\(\dfrac{s}{t}\),由于\(\dfrac{1}{t-i} > \dfrac{1}{t}(i \geq 1)\),故\(\sum\limits_{i=0}^{s-1}\dfrac{1}{t-i} > \sum\limits_{i=0}^{s-1}\dfrac{1}{t}=\dfrac{s}{t}\),所以每次\(1\)位选手答错时最终所得的美元数是最大的。
神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int main(void) {
int n;
read(n);
double ans=0;
for(int i=1;i<=n;++i) ans+=1.0/(double)(n-i+1);
printf("%.6f\n",ans);
return 0;
}
C. NEKO's Maze Game (CF 1293 C)
题目大意
给定一个\(2*n\)的矩形格子,你要从\((1,1)\)走到\((2,n)\),有\(q\)个时刻,第\(i\)个时刻,\((r_i,c_i)\)的格子的状态会翻转,即从可走变不可走,或者不可走变可走。初始所有格子可走,问每一个时刻后,你能否从\((1,1)\)走到\((2,n)\)。
解题思路
注意到不能达到的不可走格子分布只有两种,第一种是某一列的两个格子都不可走,第二种是相邻列的不同行格子都不可走,分别统计这两种的分布的数量,大于\(0\)则不可到达,否则可以到达。
神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
const int N=1e5+8;
int val[2][N],cnt,n,q;
int main(void) {
read(n);
read(q);
val[0][0]=val[1][0]=val[0][n+1]=val[1][n+1]=-1;
for(int r,c,i=1;i<=q;++i){
read(r);
read(c);
r--;
val[r][c]^=1;
if (val[r][c]==1&&val[r^1][c]==1) ++cnt;
if (val[r][c]==0&&val[r^1][c]==1) --cnt;
if (val[r][c]==1&&val[r^1][c-1]==1) ++cnt;
if (val[r][c]==0&&val[r^1][c-1]==1) --cnt;
if (val[r][c]==1&&val[r^1][c+1]==1) ++cnt;
if (val[r][c]==0&&val[r^1][c+1]==1) --cnt;
if (cnt) puts("No"); else puts("Yes");
}
return 0;
}
D. Aroma's Search (CF 1293 D)
题目大意
给定一个坐标,有好多数据包,初始数据包在位置\((x_0,y_0)\)处,之后的数据包由递推式\(x_n=a_x\times x_{n-1}+b_x,y_n=a_y\times y_{n-1}+b_y\)给出,第\(i\)个数据包编号为\(i\),坐标为\((x_i,y_i)\)。\(Aroma\ White\)的初始位置是\((x_s,y_s)\),它可以上下左右移动\(t\)次,问他最多能搜集到多少数据包。
解题思路
注意到\(a_x,a_y,b_x,b_y\)都大于\(0\),那些数据包的坐标会越来越大,它们的距离也会越来越大,故当\(Aroma\ White\)到达某个数据包时,显然我们是往标号小的数据包去跑是最好的。第\(i\)个数据包和第\(i-1\)个数据包的曼哈顿距离为\((a_x-1)*x_{i-1}+b_x+(a_y-1)*y_{i-1}+b_y\),极端情况下即是\(a_x=a_y=2,b_x=b_y=0\)的时候,这时候距离就是\(x_{i-1}+y_{i-1}\),由于\(t\leq 10^{16}\),所以数据包的坐标我们就枚举到\(10^{16}\)即可,由于递推式里坐标是指数级增长的,枚举到的数据包最多也就\(\log_2{10^{16}}\approx 53\)个,妥妥\(O({53}^2)\)暴力枚举第一个到达的数据包编号贪心求数量取最大值即可。注意如果先到达第\(k\)个数据包,最后到了第\(0\)个数据包还可以继续移动的话,还要继续枚举第\(k+1\)个数据包及以上看能否到达。
神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
const LL N=10000000000000000ll+8;
vector<pair<LL,LL>> pos;
int check(int x,LL xs,LL ys,LL t){
int cnt=0;
for(int i=x;i>=0;--i){
LL dis=abs(pos[i].first-xs)+abs(pos[i].second-ys);
if (dis<=t){
t-=dis;
xs=pos[i].first;
ys=pos[i].second;
++cnt;
}
else return cnt;
}
int len=pos.size();
for(int i=x+1;i<len;++i){
LL dis=abs(pos[i].first-xs)+abs(pos[i].second-ys);
if (dis<=t){
t-=dis;
xs=pos[i].first;
ys=pos[i].second;
++cnt;
}
else return cnt;
}
return cnt;
}
int main(void) {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
LL x0,y0,ax,ay,bx,by;
cin>>x0>>y0>>ax>>ay>>bx>>by;
LL xs,ys,t;
cin>>xs>>ys>>t;
pos.push_back(make_pair(x0,y0));
while(x0<N||y0<N){
if (x0>=ax*x0+bx) break;
x0=ax*x0+bx;
if (y0>=ay*y0+by) break;
y0=ay*y0+by;
pos.push_back(make_pair(x0,y0));
}
int ans=0;
int len=pos.size();
for(int i=0;i<len;++i)
ans=max(ans,check(i,xs,ys,t));
cout<<ans<<endl;
return 0;
}
~~第一次交MLE怀疑人生??我就53个点怎么MLE??后来发觉是long long溢出导致枚举数据包停不下来了~~