测试「2020牛客NOIP赛前集训营-提高组(第五场)」
T1
签到题。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e6+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n;
lxl ans;
int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
#endif
read(n);
for(int i=1;i<=n;++i)
for(int j=i<<1;j<=n;j+=i)
ans+=(n-j)/j;
printf("%lld\n",ans);
return 0;
}
T2
找到 \(T\) 在 \(S\) 中出现的所有位置计数即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e7+5;
const lxl mod=998246353;
const lxl p=233;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,k;
char s[maxn],t[maxn];
lxl hshs[maxn],hsht,P[maxn],ans;
int main()
{
#ifndef ONLINE_JUDGE
freopen("B.in","r",stdin);
#endif
read(n),read(k);
scanf(" %s %s",s+1,t+1);
P[0]=1;
for(int i=1;i<=n;++i)
hshs[i]=(hshs[i-1]*p+s[i])%mod,P[i]=(P[i-1]*p)%mod;
for(int i=1;i<=k;++i) hsht=(hsht*p+t[i])%mod;
int las=0;
for(int i=k;i<=n;++i)
if((hshs[i]-hshs[i-k]*P[k]%mod+mod)%mod==hsht)
{
if(las) ans+=1ll*(las-k+1)*(i-las);
las=i;
}
if(las) ans+=1ll*(las-k+1)*(n-las+1);
printf("%lld\n",ans);
return 0;
}
T3
将所有数丢到可持久化Trie上,然后差分求第 \(k\) 大即可。因为这道题字符串长度不一致,所以调了1h+。
然后最后30min发现可以直接预处理出所有数字的字典序,然后主席树维护,花了不到20min就调出来了/fad,赛后发现这才是正解。
\(\text{Code}:\)
可持久化Trie:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define ONLINE_JUDGE
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,q;
namespace Trie
{
int tot,rt[maxn];
int ch[maxn<<4][10],siz[maxn<<4],idx[maxn<<4];
inline void insert(int u,int x,int tmp)
{
static int buf[10],top;
top=0;int d=x;
while(d) buf[++top]=d%10,d/=10;
for(int i=top;i>=1;--i)
{
int c=buf[i];
siz[u]=siz[tmp]+1;
idx[u]=idx[tmp];
for(int j=0;j<=9;++j) ch[u][j]=ch[tmp][j];
ch[u][c]=++tot;
u=ch[u][c];
tmp=ch[tmp][c];
}
siz[u]=siz[tmp]+1;
for(int j=0;j<=9;++j) ch[u][j]=ch[tmp][j];
idx[u]=x;
}
inline int query(int pl,int pr,int k)
{
if(idx[pr]-idx[pl]!=0&&k==1) return idx[pr];
k-=(idx[pr]-idx[pl]!=0);
for(int i=0;i<=9;++i)
if(siz[ch[pr][i]]-siz[ch[pl][i]]<k)
k-=siz[ch[pr][i]]-siz[ch[pl][i]];
else return query(ch[pl][i],ch[pr][i],k);
return -1;
}
}
using Trie::rt;
using Trie::tot;
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
#endif
read(n),read(q);
for(int i=1,x;i<=n;++i)
{
read(x);
Trie::insert(rt[i]=++tot,x,rt[i-1]);
}
int l,r,k;
while(q--)
{
read(l),read(r),read(k);
printf("%d\n",Trie::query(rt[l-1],rt[r],k));
}
return 0;
}
主席树:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define ONLINE_JUDGE
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e5+5;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,q;
int val[maxn],a[maxn];
struct number
{
int dig[10],len,x;
number(int x):x(x)
{
len=0;
while(x) dig[++len]=x%10,x/=10;
for(int i=1;(1<<i)<=len;++i)
swap(dig[i],dig[len-i+1]);
}
number(){}
inline bool operator < (const number &T)const
{
int L=min(len,T.len);
for(int i=1;i<=L;++i)
if(dig[i]!=T.dig[i]) return dig[i]<T.dig[i];
return len<T.len;
}
}num[maxn];
namespace Segment_Tree
{
int tot;
int sum[maxn<<5],ch[maxn<<5][2];
void modify(int &p,int l,int r,int ps,int tmp)
{
p=++tot;
sum[p]=sum[tmp]+1;
ch[p][0]=ch[tmp][0];ch[p][1]=ch[tmp][1];
if(l==r) return;
int mid=(l+r)>>1;
if(ps<=mid) modify(ch[p][0],l,mid,ps,ch[tmp][0]);
else modify(ch[p][1],mid+1,r,ps,ch[tmp][1]);
}
int query(int pl,int pr,int l,int r,int k)
{
if(l==r) return (sum[pr]-sum[pl]&&k==1)?num[l].x:-1;
int mid=(l+r)>>1;
if(sum[ch[pr][0]]-sum[ch[pl][0]]>=k)
return query(ch[pl][0],ch[pr][0],l,mid,k);
else return query(ch[pl][1],ch[pr][1],mid+1,r,k-(sum[ch[pr][0]]-sum[ch[pl][0]]));
}
}
int rt[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("C.in","r",stdin);
freopen("baoli.out","w",stdout);
#endif
read(n),read(q);
for(int i=1;i<=n;++i)
{
read(a[i]);
num[i]=number(a[i]);
}
sort(num+1,num+n+1);
for(int i=1;i<=n;++i)
val[num[i].x]=i;
for(int i=1;i<=n;++i)
Segment_Tree::modify(rt[i],1,n,val[a[i]],rt[i-1]);
int l,r,k;
while(q--)
{
read(l),read(r),read(k);
printf("%d\n",Segment_Tree::query(rt[l-1],rt[r],1,n,k));
}
return 0;
}
T4
容易发现这是一个树形结构,每个圆向包含它的最小的圆连边,现在问题就是如何找到这个圆。
用扫描线从左往右扫,用set记录扫描线与圆的交点,按纵坐标排序。每次新加入一个圆时,查找它上面第一个圆弧,若这个圆弧是上半圆弧,那么这个圆弧对应的圆就是这个圆的父亲,否则就是它的兄弟。
建完树求LCA即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <set>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=1e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
struct edge
{
int u,v,next;
edge(int u,int v,int next):u(u),v(v),next(next){}
edge(){}
}e[maxn];
int head[maxn],ecnt;
inline void add(int u,int v)
{
e[ecnt]=edge(u,v,head[u]);
head[u]=ecnt++;
}
int n,q;
namespace Tree
{
int dep[maxn],fa[maxn],top[maxn],son[maxn],siz[maxn];
void dfs1(int u)
{
dep[u]=dep[fa[u]]+1;
siz[u]=1;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==son[u]) continue;
dfs2(v,v);
}
}
inline int LCA(int a,int b)
{
for(;top[a]!=top[b];dep[top[a]]>dep[top[b]]?a=fa[top[a]]:b=fa[top[b]]);
return dep[a]<dep[b]?a:b;
}
}
using Tree::dep;
using Tree::fa;
struct circle
{
int x,y,r;
circle(int x,int y,int r):x(x),y(y),r(r){}
circle(){}
}cir[maxn];
struct Time
{
int x,id,type;
Time(int x,int id,int type):x(x),id(id),type(type){}
Time(){}
inline bool operator < (const Time &T)const
{
return x<T.x;
}
}t[maxn<<1];
int tcnt;
int now;
struct node
{
int id,type;
node(int id,int type):id(id),type(type){}
node(){}
inline double calcu()const
{
return (double)cir[id].y+
(double)type*sqrt((double)cir[id].r*cir[id].r-(double)(cir[id].x-now)*(cir[id].x-now));
}
inline bool operator < (const node &T)const
{
return id==T.id?type<T.type:calcu()<T.calcu();
}
};
set<node> s;
int main()
{
#ifndef ONLINE_JUDGE
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
#endif
read(n);
for(int i=1,x,y,r;i<=n;++i)
{
read(x),read(y),read(r);
cir[i]=circle(x,y,r);
t[++tcnt]=Time(x-r,i,1);
t[++tcnt]=Time(x+r,i,-1);
}
sort(t+1,t+tcnt+1);
for(int i=1;i<=tcnt;++i)
{
now=t[i].x;
if(t[i].type==1)
{
auto it=s.upper_bound(node(t[i].id,1));
if(it==s.end()) fa[t[i].id]=n+1;
else if(it->type==1) fa[t[i].id]=it->id;
else fa[t[i].id]=fa[it->id];
s.insert(node(t[i].id,1));
s.insert(node(t[i].id,-1));
}
else
{
s.erase(s.find(node(t[i].id,1)));
s.erase(s.find(node(t[i].id,-1)));
}
}
memset(head,-1,sizeof(head));
for(int i=1;i<=n;++i)
add(fa[i],i);
Tree::dfs1(n+1);
Tree::dfs2(n+1,n+1);
read(q);
int u,v;
while(q--)
{
read(u),read(v);
int f=Tree::LCA(u,v);
printf("%d\n",dep[u]+dep[v]-2*dep[f]-(u!=f)-(v!=f));
}
return 0;
}