[Educational Codeforces Round#22]

Posted FallDream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Educational Codeforces Round#22]相关的知识,希望对你有一定的参考价值。

来自FallDream的博客,未经允许,请勿转载,谢谢。


晚上去clj博客逛来逛去很开心,突然同学提醒了一下,发现cf已经开始40分钟了,慌的一B,从B题开始写,写完了B到E最后收掉了A,结果太着急B题忘记写一个等号挂掉了。。。。D题瞎dp也挂了很难受。F题还剩5分钟的时候想出来了,如果没迟应该能写完。

A.

你要做n道题 每道题要花费时间ti,有m个可以提交的时间段,你在同一时刻可以交很多代码并且不耗时间,求最早什么时候可以把代码全部交完。

发现只要管最后一道题啥时候交就行了,扫一遍区间。

#include<iostream>
#include<cstdio>
#define MN 1000
#define INF 1000000000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < 0 || ch > 9){ if(ch == -) f = -1;  ch = getchar();}
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return x * f;
}
int n,m,mn=INF,tot=0;
int main()
{
    n=read();
    for(int i=1;i<=n;++i) tot+=read();
    m=read();
    for(int i=1;i<=m;++i)
    {
        int l=read(),r=read();
        if(r>=tot) mn=min(mn,max(0,l-tot));
    }
    printf("%d",mn==INF?-1:mn+tot);
    return 0;
}

B.给定一个区间[l,r]和x,y,定义特殊数字是可以被表示成x^a+y^b(a,b是非负整数)的数,求[l,r]中最长的连续的一段数字,满足这段数字区间内全是非特殊的数字。

l,r<=10^18 2<=x,y<=10^19

显然x^a和y^b只有log种,都拿出来排个序就行了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define MN (ll)1e18
using namespace std;
ll s[10005],s2[10005],mx=0,a[10005];int top1=0,top2=0,top=0;
int main()
{
    ll x,y,l,r;
    scanf("%lld%lld%lld%lld",&x,&y,&l,&r);
    s[++top1]=1;s2[++top2]=1;
    for(ll i=x;;i*=x)
    {
        s[++top1]=i;
        if(i>MN/x)break;
    }
    for(ll i=y;;i*=y)
    {
        s2[++top2]=i;
        if(i>MN/y)break;
    }
    for(int i=1;i<=top1;++i)
        for(int j=1;j<=top2;++j)
            if(s[i]+s2[j]>=l&&s[i]+s2[j]<=r)
                a[++top]=s[i]+s2[j];
    if(!top) return 0*printf("%lld",r-l+1);
    sort(a+1,a+top+1);
    mx=max(mx,a[1]-l);
    mx=max(mx,r-a[top]);
    for(int i=2;i<=top;++i)
        mx=max(mx,a[i]-a[i-1]-1);
    cout<<mx;
    return 0;
}

C.

给定一棵树,一个人在x(x!=1)号点,另一个在1号点,每次行动每个人可以移动到一个相邻节点或者不动,第一个人希望回合最多,第二个人希望最少,求最多有多少个回合。

n<=2*10^5

枚举目标点,一个点可行当且仅当x到它和x的lca的距离小于1号点到lca的距离。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MD 18
#define MN 200000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < 0 || ch > 9){ if(ch == -) f = -1;  ch = getchar();}
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return x * f;
}
pair<int,int> p[MN+5];
int cnt=0,head[MN+5],fa[MD+5][MN+5],dep[MN+5],f[MN+5],n;
struct edge{int to,next;}e[MN*2+5];
inline void ins(int f,int t)
{
    e[++cnt]=(edge){t,head[f]};head[f]=cnt;
    e[++cnt]=(edge){f,head[t]};head[t]=cnt;
}
bool cmp(pair<int,int> x,pair<int,int> y){return x.first>y.first;}
void Dfs(int x,int f)
{
    fa[0][x]=f;p[x]=make_pair(dep[x],x);
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f)
            dep[e[i].to]=dep[x]+1,Dfs(e[i].to,x);
}

inline int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
        if(k&1)x=fa[j][x];
    if(x==y) return x;
    for(int i=MD;~i;--i)
        if(fa[i][x]!=fa[i][y])
            x=fa[i][x],y=fa[i][y];
    return fa[0][x];
}

int main()
{
    n=read();int x=read();
    for(int i=1;i<n;++i) ins(read(),read());
    Dfs(1,0);
    for(int i=1;i<=MD;++i)
        for(int j=1;j<=n;++j)
            fa[i][j]=fa[i-1][fa[i-1][j]];
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;++i)
    {
        int z=lca(x,p[i].second);
        if(dep[x]-dep[z]>=dep[z]) continue;
        return 0*printf("%d\n",p[i].first*2);
    }
    return 0;
}

D.

给定一个长度为n(<=5000)的序列ai,定义优秀的序列是满足相邻元素相差1或者在膜7意义下相等的序列,求这个序列的两个不相交的优秀子序列满足长度之和最大。

f[i][j]表示两个序列结尾分别在i,j的最长长度

枚举i,j,对于每个i,开两个数组分别表示最后一个数是k和最后一个数膜7等于k的最长长度,然后分别转移。

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 5000
using namespace std;
inline int read()
{
    int x = 0,f = 1; char ch = getchar();
    while(ch < 0 || ch > 9){if(ch == -) f = 0;ch = getchar();}
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return f?x:-x;
}
int n,a[MN+5],f[MN+5],F[8],D[MN+5][MN+5],ans=0,ha[100005],cnt=0;
inline void R(int&x,int y){y>x?x=y:0;}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)!ha[a[i]=read()]?ha[a[i]]=++cnt:0;
    for(int i=0;i<=n;++i)
    {
        memset(F,0,sizeof(F));
        memset(f,0,sizeof(f));
        int Mx=D[i][0];
        for(int j=1;j<i;++j)
            R(F[a[j]%7],D[i][j]),
            R(f[ha[a[j]]],D[i][j]);
        for(int j=i+1;j<=n;++j)
        {
            R(D[i][j],Mx+1);
            R(D[i][j],max(f[ha[a[j]]],F[a[j]%7])+1);
            if(ha[a[j]-1]) R(D[i][j],f[ha[a[j]-1]]+1);
            if(ha[a[j]+1]) R(D[i][j],f[ha[a[j]+1]]+1);
            R(F[a[j]%7],D[i][j]);R(f[ha[a[j]]],D[i][j]);
            R(D[j][i],D[i][j]);R(ans,D[i][j]);
        }
    }
    cout<<ans;
    return 0;
}

E. Army Creation

给定一个长度为n(<=100000)的序列ai,每次询问一段区间,满足每个数字出现次数不超过k(预先给定)次的情况下最多能保留几个数字。

从前往后扫一遍,找到每个数字前面的第k个相同的数字的位置pos,右区间>=i且左区间<=pos的时候答案减1,可持久化线段树维护即可。

复杂度nlogn

#include<iostream>
#include<cstdio>
#include<vector>
#define MN 100000
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < 0 || ch > 9){ if(ch == -) f = -1;  ch = getchar();}
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return x * f;
}
vector<int> v[MN+5];
int n,k,num[MN+5],rt[MN+5],cnt=0,last=0,a[MN+5];
struct Tree{int l,r,x;}T[5000000];

void Modify(int x,int nx,int k)
{
    int l=1,r=n,mid;T[nx].x=T[x].x+1;
    while(l<r)
    {
        mid=l+r>>1;
        if(k<=mid)T[nx].r=T[x].r,T[nx].l=++cnt,x=T[x].l,nx=T[nx].l,r=mid;
        else T[nx].l=T[x].l,T[nx].r=++cnt,x=T[x].r,nx=T[nx].r,l=mid+1;
        T[nx].x=T[x].x+1;
    }
}

int Query(int x,int k)
{
    int sum=0,l=1,r=n,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(k<=mid) sum+=T[T[x].r].x,x=T[x].l,r=mid;
        else x=T[x].r,l=mid+1;
    }
    return sum+T[x].x;
}

int main()
{
    n=read();k=read();
    for(int i=1;i<=n;++i)
        v[a[i]=read()].push_back(i);
    for(int i=1;i<=n;++i)
        if(++num[a[i]]>k)
            Modify(rt[i-1],rt[i]=++cnt,v[a[i]][num[a[i]]-k-1]);
        else rt[i]=rt[i-1];
    for(int q=read();q;--q)
    {
        int l=(read()+last)%n+1,r=(read()+last)%n+1;
        if(l>r) swap(l,r);
        printf("%d\n",last=(r-l+1)-Query(rt[r],l));
    }
    return 0;
}

F.

给你n个点,支持删边,加边,询问是否是二分图。

n,q<=10^5

考虑线段树分治避免删除操作,然后带权并差集+启发式合并维护答案即可。

复杂度nlog^2n

#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define MN 100000
using namespace std;
inline int read()
{
    int x = 0,f = 1; char ch = getchar();
    while(ch < 0 || ch > 9){if(ch == -) f = 0;ch = getchar();}
    while(ch >= 0 && ch <= 9){x = x * 10 + ch - 0;ch = getchar();}
    return f?x:-x;
}
bool Ans[MN+5];
map<long long,int> mp;
int n,q,cnt=1,fa[MN+5],W[MN+5],val[MN+5],size[MN+5],A[MN+5],B[MN+5];
struct Tree{int l,r;vector<pa> x;vector<int> v;}T[MN*4+5];

void Ins(int x,int l,int r,pa v)
{
    if(T[x].l==l&&T[x].r==r) {T[x].x.push_back(v);return;}
    int mid=T[x].l+T[x].r>>1;
    if(r<=mid) Ins(x<<1,l,r,v);
    else if(l>mid) Ins(x<<1|1,l,r,v);
    else Ins(x<<1,l,mid,v),Ins(x<<1|1,mid+1,r,v);
}

void build(int x,int l,int r)
{
    if((T[x].l=l)==(T[x].r=r))return;
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
inline int getfa(int x)
{
    if(fa[x]==x) return x;
    int F=getfa(fa[x]);
    return val[x]=val[fa[x]]^W[x],F;
}
void Solve(int k,bool flag)
{
    for(int i=0;i<T[k].x.size();++i)
    {
        int x=T[k].x[i].first,y=T[k].x[i].second;
        int f1=getfa(x),f2=getfa(y);
        if(size[f1]>size[f2]) swap(f1,f2);
        if(f1==f2) flag|=(val[x]==val[y]);
        else
        {
            size[f2]+=size[f1];fa[f1]=f2;
            W[f1]=val[x]==val[y];
            T[k].v.push_back(f1);
        }
    }
    if(T[k].l==T[k].r) Ans[T[k].l]=flag;
    else Solve(k<<1,flag),Solve(k<<1|1,flag);
    for(int i=0;i<T[k].v.size();++i)
    {
        int x=T[k].v[i];fa[x]=x;
        size[fa[x]]-=size[x];W[x]=val[x]=0;
    }
}

int main()
{
    n=read();q=read();build(1,1,q);
    for(int i=1;i<=n;++i) fa[i]=i,size[i]=1,val[i]=W[i]=0;
    for(int i=1;i<=q;++i)
    {
        int x=read(),y=read();
        if(mp[1LL*x*MN+y])
        {
            Ins(1,mp[1LL*x*MN+y],i-1,mp(x,y));
            mp[1LL*x*MN+y]=0;
        }
        else mp[1LL*x*MN+y]=i;
        A[i]=x;B[i]=y;
    }
    for(int i=1;i<=q;++i)
    {
        int x=mp[1LL*A[i]*MN+B[i]];
        if(x) mp[1LL*A[i]*MN+B[i]]=0,Ins(1,x,q,mp(A[i],B[i]));
    }
    Solve(1,0);
    for(int i=1;i<=q;++i) puts(Ans[i]?"NO":"YES");
    return 0;
}

以上是关于[Educational Codeforces Round#22]的主要内容,如果未能解决你的问题,请参考以下文章

Educational Codeforces Round 28 F. Random Query

Educational Codeforces Round 10 D. Nested Segments (树状数组)

Educational Codeforces Round 78

Educational Codeforces Round 58 (Rated for Div. 2) 题解

Educational Codeforces Round 83 --- F. AND Segments

Educational Codeforces Round 57 Solution