A题
题意
有一段序列(a_1,a_2,...,a_n,b_1,b_2,...,b_n,c_1,c_2,...c_n),找到一段序列(p_1,p_2,...,p_n),满足
- (p_iin {a_i,b_i,c_i})
- (p_i eq p_{(imod n)+1})。保证(a_i eq b_i,a_i eq c_i,b_i eq c_i)。
题解
有了这个保证这题就非常简单了,首先(p_1)可以在对应的三个数中随便选一个,再依次选(p_2,p_3...p_n),每次选的时候注意不要与前面一个数相同,最后选(p_n)时注意不要与(p_1)相同。这样随便选是一定保证能选到的,因为每个数有三个选择,相邻两个数最多只能去除两个选择,所以不管相邻数怎么选,你一定能选到值。
时间复杂度为(O(n))
代码
/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/9/30 22:26:59
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define LL long long
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e5+10;
int n,a[maxx][5],p[maxx];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int T=read();
while(T--){
n=read();
For(i,1,n) a[i][0]=read();
For(i,1,n) a[i][1]=read();
For(i,1,n) a[i][2]=read();
p[1]=a[1][0];
For(i,2,n-1)
For(j,0,2)
if(a[i][j]!=p[i-1]){
p[i]=a[i][j];
break;
}
For(j,0,2)
if(a[n][j]!=p[n-1] && a[n][j]!=p[1]){
p[n]=a[n][j];
break;
}
For(i,1,n) printf("%d ",p[i]);
printf("
");
}
return 0;
}
B题
题意
你有一个不下降序列(a_1,a_2,a_3,..a_n),并给定一个整数k,你想找m个不下降序列(b_1,b_2,...,b_n)满足
- (b_i)的长度为n
- 对任意(1leq j leq n),(a_j=b_{1,j}+b_{2,j}+...+b_{m,j})
- (b_i)中不同的数不超过k个
求满足题意最小的m,如果不存在输出-1。
题解
这题竟然WA了两发,把ceil写成四舍五入我也是醉了
这题就是让我们每次给a数组每个数减去一个b数组,多少次能把a全部减为0
- 考虑如果k等于1,那么a序列所有数相同时则m为1,否则输出-1
- 如果k不为1,我们可以发现只有构造(b_1)时我们可以消除a中k个数,之后每次构造最多只能消去k-1个数,于是答案为(max(1,1+lceil frac{cnt-k}{k-1} ceil))
时间复杂度为(O(1))
代码
/*************************************************************************
> File Name: 2.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/9/30 23:46:47
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define LL long long
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e5+10;
int a[maxx],n,k;
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int T=read();
while(T--){
n=read(); k=read();
For(i,1,n) a[i]=read();
int x=a[1],cnt=1;
For(i,2,n)
if(a[i]!=x){
++cnt;
x=a[i];
}
if(k==1){
if(cnt>1) printf("-1
");
else printf("1
");
}
else{
if(cnt<=k) printf("1
");
else{
int ans=ceil((cnt-k)/(double)(k-1));
printf("%d
",ans+1);
}
}
}
return 0;
}
C题
题意
有两辆小车从0,l坐标位置相向而行,初始车速为每秒一个单位。途中有很多特殊坐标(a_1,a_2,..a_k),每经过一个特殊坐标后车速+1。求两车相遇时间。
题解
先计算出每辆车到达每个特殊点位置的时间再根据这些时间判断在哪一段相遇,对相遇段用小学二年级学过的相遇问题公式求解(路程=速度和*时间)。具体细节见代码
时间复杂度为(O(k))
代码
/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/9/30 23:06:35
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define LL long long
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e5+10;
int n,l;
double a[maxx],t[maxx],m[maxx];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int T=read();
while(T--){
n=read(); l=read();
For(i,1,n) a[i]=read();
a[0]=0; a[n+1]=l;
t[0]=m[n+1]=0;
For(i,1,n+1){
t[i]=t[i-1]+(a[i]-a[i-1])/(double)i;
// printf("%.6lf
",t[i]);
}
int j=0;
Rep(i,n,0){
++j;
m[i]=m[i+1]+(a[i+1]-a[i])/(double)j;
// printf("%.6lf
",m[i]);
}
double ans=0.0;
For(i,0,n){
if(t[i]==m[i]){
ans=t[i];
break;
}
else if(t[i+1]==m[i+1]){
ans=t[i+1];
break;
}
else if(t[i]<m[i] && t[i+1]>m[i+1]){
// printf("%d
",i);
double s=a[i+1]-a[i];
if(t[i]>m[i+1]){
s-=(double)(n-i+1)*(t[i]-m[i+1]);
ans=s/(double)(n+2)+t[i];
}
else{
s-=(double)(i+1)*(m[i+1]-t[i]);
ans=s/(double)(n+2)+m[i+1];
}
break;
}
}
printf("%.14lf
",ans);
}
return 0;
}
D题
题意
在一个二维平面上有n个盗贼,对应坐标((a_1,b_1),(a_2,b_2),...(a_n,b_n)),有m个探照灯,对应坐标((c_1,d_1),(c_2,d_2),..,(c_m,d_m))。每次操作可以让所有盗贼横坐标+1,或者纵坐标+1,问最少多少次操作后使任意盗贼i的坐标对任意探照灯j满足(a_i>c_j,b_i>d_j)。输入保证所有坐标都在(10^6)以内。
题解
啊,这题没做出来,我是没想到的。可能是B题莫名WA太久了,C题调太久了,时间紧张下的缘故吧
- 这题首先根据探照灯坐标求一个后缀最大值得到数组h[i]:表示每个横坐标下纵坐标至少要达到的高度。
- 接着计算每个盗贼横坐标移动对应步数后纵坐标还需上移的步数,并按横坐标排序
- 枚举横坐标的移动步数从全部盗贼移出区域到横坐标不动,由第二步得到的数组更新每个横坐标移动步数下纵坐标需要移动的最大值,求和
时间复杂度为(O(nm + nmlog (nm)+ d))
代码
/*************************************************************************
> File Name: 2.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/10/1 0:25:18
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define LL long long
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=1e6+10;
int n,m,h[maxx],nxt[maxx],cnt=0,r=0;
struct node{
int x,y;
bool operator <(const node &a) const{
return x<a.x;
}
}a[2020],b[2020],q[2005*2005];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
int u,v;
n=read(); m=read();
For(i,1,n) a[i].x=read(), a[i].y=read();
sort(a+1,a+n+1);
For(i,1,m){
u=read(); v=read();
h[u]=max(h[u],v);
r=max(r,u);
}
int height=0; v=0;
for(int i=r;i>=0;--i){
nxt[i]=v;
if(h[i]>height){
height=h[i];
v=i;
}
else h[i]=height;
}
For(i,1,n){
int j=nxt[a[i].x];
q[++cnt]=(node){0,i};
while(j){
q[++cnt].x=j-a[i].x;
q[cnt].y=i;
j=nxt[j];
}
}
sort(q+1,q+cnt+1);
int d=r+1-a[1].x,ans=max(d,0),mx=0;
for(int i=d-1;i>=0;--i){
while(cnt && q[cnt].x==i){
int id=q[cnt].y,pos=a[id].x+i;
mx=max(mx,h[pos]+1-a[id].y);
--cnt;
}
ans=min(ans,i+mx);
}
printf("%d
",ans);
return 0;
}