距离 AK 最近的一次,死因是没搜出 G 题原题。

A - Timeout

\(T_{0}=0\),然后对于 \(i\in [1,n]\) 依次检查是否存在 \(T_i-T_{i-1}>S\),如果有,即为 No,反之则 Yes

时间复杂度 \(O(n)\)。

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N=1005;
int n,t[N],s;
int main(){
scanf("%d %d",&n,&s);
for(int i=1;i<=n;i++){
scanf("%d",t+i);
if(t[i]-t[i-1]>s){
printf("No\n");
return 0;
}
}
printf("Yes\n");
return 0;
}

B - Compression

记录下来排序离散化即可。

时间复杂度 \(O(n\log n)\)。

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1005;
int n,a[N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",a+i);
sort(a+1,a+1+n);
n=unique(a+1,a+1+n)-(a+1);
printf("%d\n",n);
for(int i=1;i<=n;i++)printf("%d ",a[i]);
return 0;
}

C - Not All Covered

将每个防御塔视作一个区间,就是找那个塔被覆盖次数最少。

注意到查询在修改之后,区间加单点查,可以利用差分数组。

时间复杂度 \(O(n+m)\)。

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int n,c[N],m,l,r,ans;
int main(){
scanf("%d %d",&n,&m);
while(m--){
scanf("%d %d",&l,&r);
c[l]++,c[r+1]--;
}
ans=c[1];
for(int i=1;i<=n;i++)c[i]+=c[i-1],ans=min(ans,c[i]);
printf("%d\n",ans);
return 0;
}

D - Flip to Gather

假设 \(1\sim i\) 中 \(1\) 的个数记为 \(s_i\),\(i\sim n\) 的个数记为 \(p_i\)。则整个字符串内只有 \([l,r]\) 内全为 1 的代价为

\[s_{l-1}+p_{r+1}+(r-l+1)-(s_r-s_{l-1})
\]

将 \(l,r\) 相关的部分分开,即为:

\[(p_{r+1}+r+1-s_r)+(2s_{l-1}-l)
\]

枚举 \(r\),用前缀和记录 \((2s_{l-1}-l)\) 的最小值更新即可,注意特判全为 \(0\) 的字符串。

时间复杂度 \(O(Tn)\)。

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=2e5+10;;
int T,n,s[N],p[N],mn,ans;
char t[N];
void work(){
scanf("%d",&n);
scanf("%s",t+1);
for(int i=1;i<=n;i++)s[i]=(t[i]=='1'),p[i]=(t[i]=='1');
s[0]=p[n+1]=0;//清空
for(int i=1;i<=n;i++)s[i]+=s[i-1];
for(int i=n;i>=1;i--)p[i]+=p[i+1];
if(!s[n]){
printf("0\n");
return;
}
mn=0;ans=1e9;
for(int i=1;i<=n;i++){
mn=min(mn,-i+2*s[i-1]);
ans=min(ans,p[i+1]+i+1-s[i]+mn);
}
printf("%d\n",ans);
return;
}
int main(){
scanf("%d",&T);
while(T--)work();
return 0;
}

E - Minimum OR Path

因为 OR 运算的性质,只要 \(1\to n\) 的路径上有一条边的第 \(k\) 位为 \(1\),那么最终结果第 \(k\) 位即为 \(1\),所以我们要使最终结果第 \(k\) 位不为 \(1\),则只能走第 \(k\) 位为 \(0\) 的边。

从高到低逐位确定答案,假设当前已经确定了 \(k+1\sim 30\) 位,且只通过没有打标记的边,那么我们看看如果只走第 \(k\) 位为 \(0\) 的边,能否从 \(1\to n\),我们可以维护一个并查集,若一条边 \((u,v,w)\) 没有被打标记,且 \(w\) 第 \(k\) 位为 \(0\),则将 \(u,v\) 所在集合合并。

  • 如果最后 \(1,n\) 不在同一集合。

说明第必须经过第 \(k\) 位为 \(1\) 的边,让答案或上 \(2^k\)。

  • 如果最后 \(1,n\) 在同一集合。

说明可以不经过第 \(k\) 位为 \(1\) 的边,则经过第 \(k\) 位为 \(1\) 的边一定不优,把这些没打上标记,但第 \(k\) 位为 \(1\) 的边打上标记。

这让从 \(30\sim 0\) 逐位枚举即可。时间复杂度 \(O(n\log n\log V)\)。

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N=2e5+10;
int n,m,u[N],v[N],w[N],mk[N],f[N],ans;
void reset(){
for(int i=1;i<=n;i++)f[i]=i;
}
int found(int x){
return f[x]==x?x:f[x]=found(f[x]);
}
bool check(int k){
reset();
for(int i=1;i<=m;i++){
if(mk[i])continue;
if(!((w[i]>>k)&1)){
int x=found(u[i]);
int y=found(v[i]);
if(x!=y)f[x]=y;
}
}
return (found(1)==found(n));
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d %d %d",u+i,v+i,w+i);
for(int i=30;i--;i>=1){
if(check(i)){
for(int j=1;j<=m;j++){
if(mk[j])continue;
if((w[j]>>i)&1)mk[j]=1;
}
}else ans|=(1<<i);
}
printf("%d\n",ans);
return 0;
}

F - Athletic

注意到无论怎么爬梯子都是越爬越低,显然可以设计 dp,按照高度从高到低为顺序状态转移。

\(dp_i\) 可以转移的范围是 \([i-r,i+r]\) 的最大 dp 值,最大+区间,不难想到线段树,另一个关键的限制在于 \(H_i\le H_j-D\),我们可以用可持久化线段树来完成这一限制,不过太过麻烦。

注意到 \(H_i\) 为 \(n\) 的一个排列,所以第 \(i\) 个转移的 dp 值可以转移的是 \(i-D\) 之前的 dp 值,所以当我们将第 \(i\) 个 \(dp\) 值插入线段树时,让第 \(i+D\) 个 dp 值进行转移即可。

时间复杂度 \(O(n\log n)\),不懂的可以看代码。

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ls (p<<1)
#define rs (p<<1|1)
using namespace std;
const int N=5e5+10;
const int inf=1e9;
struct sgt{
int mx[N<<2];
void push_up(int p){
mx[p]=max(mx[ls],mx[rs]);
}
void build(int p,int l,int r){
mx[p]=-inf;
if(l==r)return;int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void change(int p,int l,int r,int x,int v){
if(l==r)mx[p]=max(mx[p],v);
else{
int mid=(l+r)>>1;
if(x<=mid)change(ls,l,mid,x,v);
if(x>mid)change(rs,mid+1,r,x,v);
push_up(p);
}
}
int ask(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return mx[p];
int mid=(l+r)>>1,res=-inf;
if(L<=mid)res=max(res,ask(ls,l,mid,L,R));
if(R>mid)res=max(res,ask(rs,mid+1,r,L,R));
return res;
}
}tr;
struct node{
int h,id,dp;
}a[N];
bool cmp(node a,node b){
return a.h>b.h;
}
int n,d,r,ans;
int main(){
scanf("%d %d %d",&n,&d,&r);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].h);
a[i].id=i,a[i].dp=1;
}
tr.build(1,1,n);
sort(a+1,a+1+n,cmp);
for(int i=1,j;i<=n;i++){
tr.change(1,1,n,a[i].id,a[i].dp);
j=i+d;
if(j<=n){
int val=tr.ask(1,1,n,max(1,a[j].id-r),min(n,a[j].id+r));
val=max(val,0)+1,a[j].dp=max(a[j].dp,val);
}
}
for(int i=1;i<=n;i++)ans=max(ans,a[i].dp);
printf("%d\n",ans-1);
return 0;
}

G - A/B < p/q < C/D

原题,但是不会/kel。

分类讨论:

  1. \(a<b,c>d\)

此时有 \(\dfrac{a}{b}<1<\dfrac{c}{d}\),直接构造 \(p=1,q=1\) 即可。

  1. 其他情况。

将不等式都取倒数,即可得到:

\[\dfrac{d}{c}<\dfrac{q}{p}<\dfrac{b}{a}
\]

把这个东西第一项约真分数:

\[\dfrac{d\bmod c}{c}=\dfrac{d-\left\lfloor\dfrac{d}{c}\right\rfloor c}{c}
\]

更具不等式的性质,不等式两侧同时减去 \(\left\lfloor\dfrac{d}{c}\right\rfloor\):

\[\dfrac{d-\left\lfloor\dfrac{d}{c}\right\rfloor c}{c}<\dfrac{q-\left\lfloor\dfrac{d}{c}\right\rfloor p}{p}<\dfrac{b-\left\lfloor\dfrac{d}{c}\right\rfloor a}{a}
\]

另 \(a'=d-\left\lfloor\dfrac{d}{c}\right\rfloor c,b'=c,p'=q-\left\lfloor\dfrac{d}{c}\right\rfloor p,q'=p,c'=b-\left\lfloor\dfrac{d}{c}\right\rfloor a,d'=a\)

这样就将情况缩小了,正确性懒得证,参考扩展欧几里得,这个辗转相除的形式类似 \(\gcd\) 时间复杂度为 \(O(T\log V)\)。代码很短。

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
void dfs(ll a,ll b,ll &p,ll &q,ll c,ll d){
if(a<b&&c>d)return p=1,q=1,void();
dfs(d%c,c,q,p,b-(d/c)*a,a);
q+=(d/c)*p;return;
}
ll a,b,c,d,x,y;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
dfs(a,b,x,y,c,d);printf("%lld\n",y);
}
return 0;
}

何时才能上青?

随机推荐

  1. 原型设计工具Axure墨刀哪个好用?

    一.工具基础特性对比 Axure为本地化安装软件,支持离线操作且数据存储本地,安全性较高,但多端协作需通过云端同步,存在更新延迟:墨刀则为云端在线工具,通过浏览器即可使用,无需安装,便于多端协作与实时 ...

  2. API接口调用--历史上的今天(v1.0)

    历史上的今天 参考(聚合数据):https://www.juhe.cn/docs/api/id/63 事件列表(v1.0) 接口地址: http://api.juheapi.com/japi/toh ...

  3. 手把手教你实现MVVM架构

    .markdown-body { color: rgba(89, 89, 89, 1); font-size: 15px; font-family: -apple-system, system-ui, ...

  4. 阿里云手工配置Nginx

    Nginx服务器是网站反向代理,负载均衡,以及动静分离的神器,由于是第一次在阿里云上配置这个,花费了大半天,终于配置成功了.下面简要的介绍下其流程,以备后面又搞忘了.前提是自动装装不上 购买阿里云服务 ...

  5. 探秘Transformer系列之(34)--- 量化基础

    探秘Transformer系列之(34)--- 量化基础 目录 探秘Transformer系列之(34)--- 量化基础 0x00 概述 0x01 背景知识 1.1 需求 1.2 压缩 1.3 如何表 ...

  6. 服务器接口附件限制【1M】解决办法

     一.业务场景:         在后端与手机小程序端接口传附件时,发现经过云服务器的接口交互,附件超过1M就会有如下提示: <html> <head><title> ...

  7. Informer架构以及简单使用

    Informer架构以及简单使用 介绍 我们知道可以使用 Clientset 来获取所有的原生资源对象,那么如果我们想要去一直获取集群的资源对象数据呢?岂不是需要用一个轮询去不断执行 List() 操 ...

  8. Django的Model类

    1.model 用来和数据交互的(读取和传入数据) 2.orm Object Relational Mapping对象关系映射,python中的model对象和数据库中的表做映射 3.重要概念 3.1 ...

  9. prometheus表达式常用公式

    1. _over_time() 下面的函数列表允许传入一个区间向量,它们会聚合每个时间序列的范围,并返回一个瞬时向量 avg_over_time(range-vector) : 区间向量内每个度量指标 ...

  10. A0-Z9

    首位字母A-Z,第二位数字0-9,组流水号. 将字母转成ascii 码,拼接数字,组成一个三位数字. 将这个三位的数字+1,再把这个三位数前两位转回字母,重新拼接出字母+数字 REPORT zlyte ...