2020.7.15集训
plan
description
在小X的家乡,有机房一条街,街上有很多机房。每个机房里都有一万个人在切题。小 X 刚刷完
,准备出来逛逛。
机房一条街有个机房,第 个机房的坐标为 ,小 X 的家坐标为 。小 X 在街上移动的速度为,即从 到 所耗费的时间为 。
每个机房的学生数量不同,ACM 题目水平也良莠不齐。小 X 到达第 个机房后,可以花 的时间
想题,然后瞬间 AK;当然,也可以过机房而不入。
小 X 现在只有 个单位时间,之后他就该赶着去打 了。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。
solution
发现我们一定不能往回走,所以可以按照坐标排个序,枚举我们最右边走到哪了,那么问题就转化成了,对于每个,前个点的最大的个要,求最大的
那么这个东西我们可以从左往右扫描,利用权值线段树维护,每次在这个权值线段树上二分就可以了
复杂度
gjm写了个的二分+堆也过了
离散化去重那里我老写不对干脆就没去重导致代码特别难看
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=1e5+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
# define int long long
int n,m;
int match[N];
struct node{
int x,t;
bool operator < (const node &cmp)const{
return x<cmp.x;
}
}a[N];
struct lsh{
int val,id;
bool operator < (const lsh &cmp)const{
return val<cmp.val;
}
}b[N];
int ans;
struct sakura{
int l,r;
int val,sum;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].val=seg[lc].val+seg[rc].val;
seg[u].sum=seg[lc].sum+seg[rc].sum;
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
void update(int u,int x,int k){
if(seg[u].l==seg[u].r){
seg[u].val++;
seg[u].sum+=k;
return;
}
int mid=seg[u].l+seg[u].r>>1;
if(x<=mid)update(lc,x,k);
else update(rc,x,k);
pushup(u);
}
int query(int u,int k){
if(seg[u].l==seg[u].r)return seg[u].val;
if(k<=seg[lc].sum)return query(lc,k);
return seg[lc].val+query(rc,k-seg[lc].sum);
}
signed main()
{
freopen("plan.in","r",stdin);
freopen("plan.out","w",stdout);
read(n),read(m);
Rep(i,1,n)read(a[i].x),read(a[i].t),b[i]=(lsh){a[i].t,i};
sort(a+1,a+n+1);
sort(b+1,b+n+1);
Rep(i,1,n)a[b[i].id].t=i,match[i]=b[i].val;
build(1,1,n);
Rep(i,1,n){
update(1,a[i].t,match[a[i].t]);
if(m>a[i].x)ans=max(ans,query(1,m-a[i].x));
}
printf("%lld\n",ans);
return 0;
}
heap
description
给定,问有多少个由的排列构成的二叉堆
注意包括小根堆和大根堆
solution
特判
只计算小根堆个数然后就可以了
用表示个节点的情况数,我们可以分别算出左右子树的节点个数
那么有
然后简单递推就可以
注意不要递归会爆炸
#include <bits/stdc++.h>
using namespace std;
# pragma GCC optimize(3)
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=5e6+5;
const int mod=1e9+7;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n;
int a[N];
int fac[N],inv[N];
int f[N],siz[N];
int ans;
int Qpow(int base,int ind){
int res=1;
while(ind){
if(ind&1)res=1ll*res*base%mod;
base=1ll*base*base%mod;
ind>>=1;
}
return res;
}
# define lc (u<<1)
# define rc (u<<1|1)
int C(int n,int m){
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
freopen("heap.in","r",stdin);
freopen("heap.out","w",stdout);
read(n);
if(n==1)return puts("1"),0;
fac[0]=inv[0]=1;
Rep(i,1,n)fac[i]=1ll*fac[i-1]*i%mod;
Rep(i,1,n)inv[i]=Qpow(fac[i],mod-2);
_Rep(u,n,1){
siz[u]=1;
if(lc<=n)siz[u]+=siz[lc];
if(rc<=n)siz[u]+=siz[rc];
}
f[0]=f[1]=1;
_Rep(u,n,1)
if(siz[u]>1)
f[siz[u]]=1ll*C(siz[u]-1,siz[lc])*f[siz[lc]]%mod*f[siz[rc]]%mod;
printf("%lld\n",1ll*f[n]*2%mod);
return 0;
}
road
description
因为一场不小的地震,Y 省 个城市之间的道路都损坏掉了,省长希望小 X 将城市之间的道路重
修一遍。
很多城市之间的地基都被地震破坏导致不能修路了,因此可供修建的道路只有 条。因为施工队伍
有限,省长要求用尽量少的道路将所有的城市连通起来,这样施工量就可以尽量少。不过,省长为了表
示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,使得该方案中最贵道路的价格和最
便宜道路的价格的差值尽量小,即使这样的方案会使总价提升很多也没关系。
小 X 现在手忙脚乱,希望你帮帮他。
solution
首先根据长度排序,然后我们想到双指针,可以用lct维护连通性,复杂度
但是同样我们也可以用dfs来解决,每次找这条路径上最短的那条删掉
但是注意删掉的边要从邻接表里面跳过去,否则复杂度不对
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=2005;
const int M=2e4+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m;
int head[N],cnt=1;
int ans=INT_MAX;
bool vis[N],able[M<<1];
struct sakura{
int x,y,c;
bool operator < (const sakura &cmp)const{
return c<cmp.c;
}
}e[M<<1];
struct Edge{
int to,next,w;
}E[M<<1];
void add(int x,int y,int c){
E[++cnt]=(Edge){y,head[x],c},head[x]=cnt;
able[cnt]=true;
}
int dfs(int u,int tar,int pre){
for(int i=head[u],last=0;~i;i=E[i].next){
int v=E[i].to;
if(!able[i]){
if(i==head[u])head[u]=E[i].next;
else E[last].next=E[i].next;
}
else{
if(v!=pre){
if(v==tar)return i;
int x=dfs(v,tar,u);
if(~x){
if(E[i].w<E[x].w)return i;
else return x;
}
}
last=i;
}
}
return -1;
}
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
memset(head,-1,sizeof(head));
read(n),read(m);
Rep(i,1,m)read(e[i].x),read(e[i].y),read(e[i].c);
sort(e+1,e+m+1);
for(int i=1,tot=0,l=1;i<=m;i++){
int nephren=dfs(e[i].x,e[i].y,-1);
if(~nephren){
tot--;
able[nephren]=able[nephren^1]=false;
while(l<=m&&!able[l*2])l++;
}
add(e[i].x,e[i].y,e[i].c);
add(e[i].y,e[i].x,e[i].c);
if(++tot==n-1)ans=min(ans,e[i].c-e[l].c);
}
printf("%d\n",ans>2e9?-1:ans);
return 0;
}
上一篇: 习题3-1 得分