「APIO 2019」奇怪装置

题目描述

有无限个二元组,每个二元组为\(((t+\left\lfloor\frac{t}{B} \right\rfloor)\%A,t \% B)\),给出一些区间,问他们之中有多少本质不同的二元组。

题解

考虑朴素做法,区间求并AC

考虑如果每个二元组为\((t\%A,t \% B)\)的话,那么它显然是有一个\(\frac{A*B}{(A,B)}\)的循环节的。

然后我们考虑所有在\(\%B\)意义下同余的所有数\(\%A\)意义下的结果。

他们形成了一个每节长度为\(B\)的一个环。

现在每个数又多了一个偏移量,相当于变成了\(B+1\)。

那么循环节就变成了\(\frac{A*B}{(A,B+1)}\)。

#include<bits/stdc++.h>
#define N 1000009
using namespace std;
typedef long long ll;
ll n,A,B,ans;
int tot;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
struct node{
ll l,r;
inline bool operator <(const node &b)const{
return l<b.l;
}
}a[N<<1];
int main(){
n=rd();A=rd();B=rd();
ll G=A/gcd(A,B+1)*B;
if(G/B!=A/gcd(A,B+1))G=9e18;
ll l,r;
for(int i=1;i<=n;++i){
l=rd();r=rd();
if(r-l+1>=G){cout<<G;return 0;}
l%=G;r%=G;
if(l>r){
a[++tot]=node{l,G-1};
a[++tot]=node{0,r};
}
else a[++tot]=node{l,r};
}
sort(a+1,a+tot+1);
ll p=0;
for(int i=1;i<=tot;++i){
p=max(p,a[i].l);
ans+=max(0ll,a[i].r-p+1);
p=max(p,a[i].r+1);
}
cout<<ans;
return 0;
}

「APIO 2019」桥梁

题目描述

无向图,边有边权,每次可以修改一条边的边权,或者询问从一个点出发走边权不小于w的边能够到达的点数。

题解

考虑朴素做法,定期重构AC

话说这不就是\([HNOI2016]\)最小公倍数吗?

然而那道题\(KD-tree\)分治能过,这题不行。

我们可以对所有操作分块,每个块内把边权不会动的边拿出来排序,会动的按照操作时间排序,每次用指针卡不会动的边,会动的暴力做就行了,做完一个快就就算所有修改。

代码

#include<bits/stdc++.h>
#define N 100002
using namespace std;
typedef long long ll;
int n,m,n1,q;
int top,top1,top2,top3,be[N],f[N],dep[N],ans[N];
int size[N],pos[N];
bool vis[N],vi[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
struct edge{
int u,v,w,id;
inline bool operator <(const edge &b)const{
return w>b.w;
}
}b[N],st1[N];
struct Q{
int opt,u,v,id,tim;
inline bool operator<(const Q &b)const{
return v>b.v;
}
}c[N],st2[N],st3[N];
struct node{
int u,v,val;
}st[N];
int find(int x){return f[x]==x?x:find(f[x]);}
inline void add(int u,int v,bool tag){
int xx=find(u),yy=find(v);
if(xx==yy)return;
if(dep[xx]>dep[yy])swap(xx,yy);
if(tag)st[++top]=node{xx,yy,dep[yy]};
f[xx]=yy;size[yy]+=size[xx];dep[yy]=max(dep[yy],dep[xx]+1);
}
inline void del(){
node x=st[top];top--;
dep[x.v]=x.val;f[x.u]=x.u;size[x.v]-=size[x.u];
}
inline int query(int x){return size[find(x)];}
int main(){
n=rd();m=rd();
int n1=max(20,(int)sqrt(max(1,m)*log2(n)));
for(int i=1;i<=m;++i){
b[i].u=rd();b[i].v=rd();b[i].w=rd();b[i].id=i;
}
sort(b+1,b+m+1);
int dd=0;
for(int i=1;i<=m;++i)pos[b[i].id]=i;
q=rd();
for(int i=1;i<=q;++i){
c[i].opt=rd();c[i].u=rd();c[i].v=rd();
c[i].tim=i;
if(c[i].opt==2)c[i].id=++dd;
}
for(int i=1;i<=q;++i)be[i]=(i-1)/n1+1;
for(int i=1;i<=be[q];++i){
int l=(i-1)*n1+1,r=min(q,i*n1);
top1=top2=top3=0;
for(int j=l;j<=r;++j)
if(c[j].opt==1)vi[c[j].u]=1,st3[++top3]=c[j];
else st2[++top2]=c[j];
sort(st2+1,st2+top2+1);
for(int j=1;j<=n;++j)f[j]=j,size[j]=dep[j]=1;
for(int j=1;j<=m;++j)if(!vi[b[j].id])st1[++top1]=b[j];
int p=1;
for(int j=1;j<=top2;++j){
while(st1[p].w>=st2[j].v&&p<=top1)add(st1[p].u,st1[p].v,0),p++;
for(int k=1;k<=top3;++k)if(st3[k].tim<st2[j].tim)vis[st3[k].u]=1;else break;
for(int k=top3;k>=1;--k){
if(st3[k].tim>st2[j].tim){
if(!vis[st3[k].u]&&b[pos[st3[k].u]].w>=st2[j].v)add(b[pos[st3[k].u]].u,b[pos[st3[k].u]].v,1);
continue;
}
if(vis[st3[k].u]&&st3[k].v>=st2[j].v)add(b[pos[st3[k].u]].u,b[pos[st3[k].u]].v,1);
vis[st3[k].u]=0;
}
ans[st2[j].id]=query(st2[j].u);
while(top)del();
}
for(int j=l;j<=r;++j){
vi[c[j].u]=0;
if(c[j].opt==1)b[pos[c[j].u]].w=c[j].v;
}
sort(b+1,b+m+1);
for(int j=1;j<=m;++j)pos[b[j].id]=j; }
for(int i=1;i<=dd;++i)printf("%d\n",ans[i]);
return 0;
}

「APIO 2019」路灯

题目描述

有一个序列,相邻两个元素之间有一个桥,每次改变一座桥的联通状态,或者询问两个点有多少时刻是联通的。

题解

考虑朴素做法,三维偏序AC

不过这个三维偏序确实比较明显,直接打个带时间戳的标记就行了。

代码

#include<bits/stdc++.h>
#define N 300009
#define ls tr[cnt].l
#define rs tr[cnt].r
using namespace std;
typedef long long ll;
char S[N];
bool nw[N];
int tot,tott,nwtim,n,q,rot;
set<int>s;
set<int>::iterator it;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
int tag;
struct point{
int x[2];
inline bool operator <(const point &b)const{
if(x[tag]!=b.x[tag])return x[tag]<b.x[tag];
else return x[tag^1]<b.x[tag^1];
}
inline bool operator ==(const point &b)const{
return x[tag]==b.x[tag]&&x[tag^1]==b.x[tag^1];
}
}b[N];
inline bool jiao(int l1,int r1,int l2,int r2){
if(l1>l2)swap(l1,l2),swap(r1,r2);
return (l2>=l1&&l2<=r1)||(r1>=l2&&r1<=r2);
}
inline bool In(int x,int l1,int r1){
return x>=l1&&x<=r1;
}
struct matrix{
point mi,mx;
};
struct seg{
int l,r;
point a,mx,mi;
int la,sum;
}tr[N];
struct Q{
int opt,x,y;
}a[N];
inline void pushdown(int cnt){
if(ls)tr[ls].sum+=tr[cnt].la,tr[ls].la+=tr[cnt].la;
if(rs)tr[rs].sum+=tr[cnt].la,tr[rs].la+=tr[cnt].la;
tr[cnt].la=0;
}
inline void pushup(int cnt){
tr[cnt].mi=tr[cnt].mx=tr[cnt].a;
for(int i=0;i<2;++i){
if(ls){
tr[cnt].mi.x[i]=min(tr[cnt].mi.x[i],tr[ls].mi.x[i]);
tr[cnt].mx.x[i]=max(tr[cnt].mx.x[i],tr[ls].mx.x[i]);
}
if(rs){
tr[cnt].mi.x[i]=min(tr[cnt].mi.x[i],tr[rs].mi.x[i]);
tr[cnt].mx.x[i]=max(tr[cnt].mx.x[i],tr[rs].mx.x[i]);
}
}
}
void build(int &cnt,int l,int r,int tg){
if(l>r)return;
if(!cnt)cnt=++tott;
int mid=(l+r)>>1;
tag=tg;
nth_element(b+l,b+mid,b+r+1);
tr[cnt].a=b[mid];
build(ls,l,mid-1,tg^1);
build(rs,mid+1,r,tg^1);
pushup(cnt);
}
inline bool pd1(matrix x,seg now){
if(x.mx.x[0]>=now.mx.x[0]&&x.mx.x[1]>=now.mx.x[1]&&x.mi.x[0]<=now.mi.x[0]&&x.mi.x[1]<=now.mi.x[1])
return 1;
return 0;
}
inline bool pd2(matrix x,seg now){
if(pd1(x,now))return 1;
if(!jiao(now.mi.x[0],now.mx.x[0],x.mi.x[0],x.mx.x[0]))return 0;
if(!jiao(now.mi.x[1],now.mx.x[1],x.mi.x[1],x.mx.x[1]))return 0;
return 1;
}
void upd(int cnt,matrix x,int y){
if(pd1(x,tr[cnt])){
tr[cnt].sum+=y;
tr[cnt].la+=y;
return;
}
if(In(tr[cnt].a.x[0],x.mi.x[0],x.mx.x[0])&&In(tr[cnt].a.x[1],x.mi.x[1],x.mx.x[1]))tr[cnt].sum+=y;
if(ls&&pd2(x,tr[ls]))upd(ls,x,y);
if(rs&&pd2(x,tr[rs]))upd(rs,x,y);
}
void query(int cnt,point x,int tg,int op){
tag=tg;
if(x==tr[cnt].a){
printf("%d\n",tr[cnt].sum+nwtim*op);
return;
}
pushdown(cnt);
if(x<tr[cnt].a)query(ls,x,tg^1,op);
else query(rs,x,tg^1,op);
}
void check(int cnt){
printf("%d %d %d %d\n",cnt,tr[cnt].a.x[0],tr[cnt].a.x[1],tr[cnt].sum);
pushdown(cnt);
if(ls)check(ls);
if(rs)check(rs);
}
int main(){
n=rd()+1;q=rd();
scanf("%s",S+1);
for(int i=1;i<=n;++i)nw[i]=S[i]-'0';
for(int i=1;i<=q;++i){
scanf("%s",S);
if(S[0]=='t'){a[i].opt=1;a[i].x=rd();}
else {a[i].x=rd();a[i].y=rd();b[++tot]=point{a[i].x,a[i].y};}
}
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-b-1;
build(rot,1,tot,0);
matrix x;
s.insert(0);s.insert(n);
for(int i=1;i<n;++i)if(!nw[i])s.insert(i);
for(int i=1;i<=q;++i){
nwtim=i;
if(a[i].opt){
if(nw[a[i].x]){
nw[a[i].x]=0;
s.insert(a[i].x);
it=s.lower_bound(a[i].x);
--it;
x.mi.x[0]=*it+1;x.mx.x[0]=a[i].x;
++it;++it;
x.mi.x[1]=a[i].x+1;x.mx.x[1]=*it;
upd(rot,x,nwtim);
}
else{
nw[a[i].x]=1;
it=s.lower_bound(a[i].x);
--it;
x.mi.x[0]=*it+1;x.mx.x[0]=a[i].x;
++it;++it;
x.mi.x[1]=a[i].x+1;x.mx.x[1]=*it;
upd(rot,x,-nwtim);
--it;
s.erase(it);
}
}
else{
it=s.lower_bound(a[i].x);
if(*it<a[i].y)query(rot,point{a[i].x,a[i].y},0,0);
else query(rot,point{a[i].x,a[i].y},0,1);
}
//check(rot);puts("");
}
return 0;
}

APIO2019解题报告的更多相关文章

  1. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  2. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  3. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  4. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  5. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

  6. 习题: codevs 2492 上帝造题的七分钟2 解题报告

    这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...

  7. 习题:codevs 1519 过路费 解题报告

    今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...

  8. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  9. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

随机推荐

  1. Python模块logging

    基本用法: import logging import sys # 获取logger实例,如果参数为空则返回root logger logger = logging.getLogger("A ...

  2. 自己手动用原生实现bind/call/apply

    自己手动用原生实现bind/call/apply:https://www.cnblogs.com/LHLVS/p/10595784.html

  3. wordpress开发的一些积累

    wordpress 攒知识点 记录开发 wordpress 的一些技能点,以备不时之需 短代码 Shortcode 虽然很多插件都是提供,直接在代码中插入类似[Shortcode] 便可以生效,但是很 ...

  4. HeidiSQL

    相关链接 https://www.heidisql.com/ - 官网 https://github.com/HeidiSQL/HeidiSQL - 源码 参考 ...

  5. 【问题解决方案】Centos操作文件vim-No write since last change (add ! to override)

    参考链接 CSDN:Centos 7 操作文件No write since last change (add ! to override) 问题描述: :q或者:wq退出失败,显示如No write ...

  6. 47. Permutations II (JAVA)

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  7. Java基础学习(1)

    Java基础知识 Java平台 1995年由Sun公司创建 Java的体系结构 JVM Java Virtue Machine Java代码的执行顺序 JDK Java Development Kit ...

  8. netstat - 显示网络连接,路由表,接口状态,伪装连接,网络链路信息和组播成员组。

    总览 SYNOPSIS netstat [address_family_options] [--tcp|-t] [--udp|-u] [--raw|-w] [--listening|-l] [--al ...

  9. windows上的QT发布

    1. 生成exe 1.1  release 条件下编译 1.2 将QT bin路径加入到path中去 1.3 将1.1生成的exe拷贝到单独的目录,然后cmd到这个目录,使用windeployqt编译 ...

  10. 一、.net core 集成vue

    一.npm安装WebPack (这种情况就会出现在项目外部,只不过借用VS的程序包管理器控制台获取而已) 右击新建项目创建webpack