[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;
}
时间: 2024-10-08 16:40:17

[Educational Codeforces Round#22]的相关文章

Educational Codeforces Round 22 E. Army Creation(主席树)

题目链接:Educational Codeforces Round 22 E. Army Creation 题意: 给你n个数和一个数k,然后有q个询问. 每个询问 有一个区间[l,r],问你这个区间内在满足每一种数不超过k的情况下,最大能选多少个数出来. 强制在线. 题解: 一看就要用到主席树,和主席数求区间内有多少不同的数的个数处理方法相同. 依次将每个数插入,当这个数出现的个数等于k了,就把最前面的那个数删掉. 然后询问就访问root[r]就行了. 第一次写完数据结构没有调试一遍过样例,一

Educational Codeforces Round 22 E. Army Creation 主席树 或 分块

E. Army Creation As you might remember from our previous rounds, Vova really likes computer games. Now he is playing a strategy game known as Rage of Empires. In the game Vova can hire n different warriors; ith warrior has the type ai. Vova wants to

【Educational Codeforces Round 22】

又打了一场EDU,感觉这场比23难多了啊-- 艹还是我太弱了. A. 随便贪心一下. #include<bits/stdc++.h> using namespace std; int n,sum=0,ans=-1,m; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 26 D. Round Subset(dp)

题目链接:Educational Codeforces Round 26 D. Round Subset 题意: 给你n个数,让你选其中的k个数,使得这k个数的乘积的末尾的0的个数最大. 题解: 显然,末尾乘积0的个数和因子2和因子5的个数有关. 然后考虑dp[i][j]表示选i个数,当前因子5的个数为j时,能得到因子2最多的为多少. 那么对于每个数,记录一下因子2和5的个数,做一些01背包就行了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) me

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu

Educational Codeforces Round 23 E. Choosing The Commander (trie)

题目链接: Educational Codeforces Round 23 E. Choosing The Commander 题意: 一共有n个操作. 1.  插入一个数p 2.  删除一个数p 3.  询问有多少个数 使得 x^p<l 题解: 对于前两种操作用01trie就能解决. 对于对三个操作,我们考虑在trie上搜索. 1.  当l的bit位是1时,那边bit位是p的字数全部的数都会小于l,(因为p^p=0) 2.  当l的bit为是0时,那边只能向bit位是p的子树中搜. 这样算下来

Educational Codeforces Round 21 D. Array Division

题目链接:Educational Codeforces Round 21 D. Array Division 题意: 给你n个数,现在你可以改变1<=个数的位置,然后问你是否存在有一个k,使得sum(a[i])(1<=i<=k)==sum(a[j])(k+1<=j<=n) 题解: 分析: 如果需要将一个数移动,无非就是将这个数从第一部分移到第二部分,或者从第二部分移到第一部分. 所以,我们只需要开两个map来记录一下两部分有哪些数. 当两部分的差值/2等于其中一部分的一个数时