Educational Codeforces Round 92 (Rated for Div. 2)

A

签到

B

直接DP,f[i][j]表示前i步j步向左的最大值,位置可以直接计算

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,k,z,ans,a[N],f[N][6];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&k,&z);
        for(int i=1;i<=n;i++)for(int j=0;j<=z;j++)f[i][j]=0;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        f[0][0]=a[1];
        for(int i=1;i<=k;i++)
        for(int j=0;j<=min(i-1,z);j++)
        {
            int pos=i-2*j;
            if(pos>1&&j<z)f[i][j+1]=max(f[i][j+1],f[i-1][j]+a[pos-1]);
            if(pos<n)f[i][j]=max(f[i][j],f[i-1][j]+a[pos+1]);
        }
        ans=0;
        for(int i=0;i<=z;i++)ans=max(ans,f[k][i]);
        printf("%d\n",ans);
    }
}
View Code

C

求最少删除次数等价于求最长序列。容易发现,最长序列有两种情况:1、全为字符a;2、长度为偶数,ababab交替。方案1记录数量最多的数字,方案2枚举ab扫描一遍即可,复杂度O(81Σn)

#include<bits/stdc++.h>
using namespace std;
int n,ans;
char s[200050];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        int num;
        ans=0;
        for(int i='0';i<='9';i++)
        {
            num=0;
            for(int j=1;j<=n;j++)if(s[j]==i)num++;
            ans=max(ans,num);
        }
        for(int a='0';a<='9';a++)
        for(int b='0';b<='9';b++)
        if(a!=b)
        {
            int now=a,num=0;
            for(int i=1;i<=n;i++)if(s[i]==now)
            {
                num++;
                now=now==a?b:a;
            }
            if(num%2)num--;
            ans=max(ans,num);
        }
        printf("%d\n",n-ans);
    }
}
View Code

D

对于两条线段,不妨三种情况:1、完全包含;2、部分包含;3、无交集。前两种直接计算,尽量改变重叠部分。第三种可以枚举改变i组线段,然后转化为第二种方案。时间复杂度O(Tn)(不然T,n给你那么小干嘛?)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
ll n,k,l1,r1,l2,r2,ans;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>k>>l1>>r1>>l2>>r2;
        if(l1>l2||l1==l2&&r1<r2)swap(l1,l2),swap(r1,r2);
        if(r1>=r2)
        {
            ll rst=(r1-l1)-(r2-l2);
            if(k<=(r2-l2)*n)puts("0");
            else if(k<=(r1-l1)*n)printf("%lld\n",k-(r2-l2)*n);
            else printf("%lld\n",rst*n+(k-(r1-l1)*n)*2);
        }
        else if(r1>=l2)
        {
            ll rst=(r2-l1)-(r1-l2);
            if(k<=(r1-l2)*n)puts("0");
            else if(k<=(r2-l1)*n)printf("%lld\n",k-(r1-l2)*n);
            else printf("%lld\n",rst*n+(k-(r2-l1)*n)*2);
        }
        else{
            ans=9e18;
            for(int i=1;i<=n;i++)
            {
                ll sum=i*(l2-r1);
                if(k<=(r2-l1)*i)sum+=k;
                else sum+=(r2-l1)*i+(k-(r2-l1)*i)*2;
                ans=min(ans,sum);
            }
            printf("%lld\n",ans);
        }
    }
}
View Code

E

老年选手不会用脑子了!若a月b日和b月a日如果是一周的同一天,则(b-1)*d+a-( (a-1)*d+b)被w整除,化简得(b-a)(d-1)%w==0,设c=b-a,则c*(d-1)%w==0。若(d-1)%w=0,则c为任意正整数 ,ans=md*(md-1)/2,md=min(m,d)。若(d-1)%w!=0,那c是lcm(w,(d-1)%w)/(d-1)%w的整数倍

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int m,d,w,g;scanf("%d%d%d",&m,&d,&w);
        g=__gcd(w,d-1),w/=g,m=min(m,d);
        long long y=m/w;
        printf("%lld\n",y*m-y*(y+1)/2*w);
    }
}
View Code

F

蒟蒻早知道看这题了,这题没有啥思维难度。根据颜色不同用2棵线段树维护DP即可。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rot 0,tot,1
using namespace std;
const int N=4e5+7;
struct ST{
    int mx[N<<2],lazy[N<<2];
    void addtag(int rt,int v){}
    void pushdown(int rt)
    {if(lazy[rt])mx[rt<<1]+=lazy[rt],lazy[rt<<1]+=lazy[rt],mx[rt<<1|1]+=lazy[rt],lazy[rt<<1|1]+=lazy[rt],lazy[rt]=0;}
    void update(int k,int v,int l,int r,int rt)
    {
        if(l==r){mx[rt]=max(mx[rt],v);return;}
        pushdown(rt);
        int m=l+r>>1;
        if(k<=m)update(k,v,lson);else update(k,v,rson);
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    }
    void add(int L,int R,int v,int l,int r,int rt)
    {
        if(L<=l&&r<=R){mx[rt]+=v,lazy[rt]+=v;return;}
        pushdown(rt);
        int m=l+r>>1;
        if(L<=m)add(L,R,v,lson);
        if(R>m)add(L,R,v,rson);
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    }
    int query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)return mx[rt];
        pushdown(rt);
        int m=l+r>>1,ret=0;
        if(L<=m)ret=max(ret,query(L,R,lson));
        if(R>m)ret=max(ret,query(L,R,rson));
        return ret;
    }
}tr[2];
struct node{int l,r,t;}a[N];
int n,tot,b[N];
bool cmp(node a,node b){return a.l<b.l;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].t),a[i].t--,b[++tot]=a[i].l,b[++tot]=a[i].r;
    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b-1;
    for(int i=1;i<=n;i++)
    a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b,a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b;
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        tr[a[i].t].update(a[i].r,max(tr[a[i].t^1].query(0,a[i].l-1,rot),tr[a[i].t].query(0,a[i].r,rot))+1,rot);
        if(a[i].r<tot)tr[a[i].t].add(a[i].r+1,tot,1,rot);
    }
    printf("%d",max(tr[0].query(0,tot,rot),tr[1].query(0,tot,rot)));
}
View Code

G

综合性很强的一题。先点双缩点,变成一个个强连通分量,然后以关键点为根,将树视为有根树,进行树上换根DP即可。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=3e5+7;
struct edge{int u,v,w;}e[N];
int n,m,cnt,rt,tot,tp,fa[N],low[N],dfn[N],st[N],bel[N],c[N],sz[N];
bool sp[N],is[N];
ll a[N],b[N],f[N],ans[N];
vector<pair<int,int> > T[N];
vector<int>G[N];
void tarjan(int u,int f)
{
    low[u]=dfn[u]=++tot,st[++tp]=u;
    for(int v:G[u])
    if(v!=f)
    {
        if(!dfn[v])tarjan(v,u),low[u]=min(low[u], low[v]);
        else low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ++cnt;int v=0;
        while(u!=v)a[bel[v=st[tp--]]=cnt]+=c[v],is[cnt]|=sp[v];
    }
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void dfs1(int u, int f)
{
    sz[u]=is[u],b[u]=a[u];
    for(auto e:T[u])
    if(e.first!=f)
    {
        dfs1(e.first,u),sz[u]+=sz[e.first];
        if(!sz[e.first])fa[e.first]=u,b[u]+=b[e.first];
    }
}
void dfs2(int u,int fa)
{
    f[u]=b[u];
    for(auto e:T[u])
    if(e.first!=fa&&sz[e.first])
    {
        dfs2(e.first, u);
        if(f[e.first]>e.second)f[u]+=f[e.first]-e.second;
    }
}
void dfs3(int u,int fa)
{
    ans[u]=f[u];
    for(auto e:T[u])
    if(e.first!=fa&&sz[e.first])
    {
        f[u]-=max(0ll,f[e.first]-e.second);
        f[e.first]+=max(0ll,f[u]-e.second);
        dfs3(e.first,u);
        f[e.first]-=max(0ll,f[u]-e.second);
        f[u]+=max(0ll,f[e.first]-e.second);
    }
}
int main()
{
    int k,x;scanf("%d%d%d",&n,&m,&k);
    while(k--)scanf("%d",&x),sp[x]=1;
    for(int i=1;i<=n;++i)scanf("%d",&c[i]);
    for(int i=1;i<=m;++i)scanf("%d",&e[i].w);
    for(int i=1;i<=m;++i)
    scanf("%d%d",&e[i].u,&e[i].v),G[e[i].u].pb(e[i].v),G[e[i].v].pb(e[i].u);
    tarjan(1,0);
    for(int i=1;i<=m;++i)
    {
        int u=bel[e[i].u],v=bel[e[i].v];
        if(u!=v)T[u].pb(make_pair(v,e[i].w)),T[v].pb(make_pair(u,e[i].w));
    }
    rt=0;
    for(int i=1;i<=cnt;++i)if(is[i])rt=i;
    for(int i=1;i<=cnt;++i)fa[i]=i;
    dfs1(rt,0),dfs2(rt,0),dfs3(rt,0);
    for(int i=1;i<=n;++i)printf("%lld ",ans[find(bel[i])]);
}
View Code

rank=216 rating+=222

新号卡线上紫啦!

posted @ 2020-07-30 09:28  hfctf0210  阅读(142)  评论(0编辑  收藏  举报