Codeforces Round #642 (Div. 3) 题解

A

序列是\(0,m,0,0,\cdots\)时有最优解。

特判一下\(n=1,2\)的情况。

int main()
{
    int T=read();
    while (T--)
    {
        ll n=read(),m=read();
        if (n==1) puts("0");
        else if (n==2) printf("%lld\n",m);
        else printf("%lld\n",m*2);
    }
    return 0;
}

B

贪心的考虑,每次操作肯定会把\(a\)中最小的换成\(b\)中最大的,如果这样做没有收益那么就停下来。

int main()
{
    int T=read();
    while (T--)
    {
        n=read();m=read();
        rep(i,1,n) a[i]=read();
        rep(i,1,n) b[i]=read();
        while (m--)
        {
            int id1=1,id2=1;
            rep(i,2,n)
                if (a[i]<a[id1]) id1=i;
            rep(i,2,n)
                if (b[i]>b[id2]) id2=i;
            if (a[id1]>b[id2]) break;
            swap(a[id1],b[id2]);
        }
        int ans=0;
        rep(i,1,n) ans+=a[i];
        printf("%d\n",ans);
    }
    return 0;
}

C

所有格子都集中到最中间的那个格子时有最优解。

枚举一下所需时间再乘一下格子数即可。

int main()
{
    int T=read();
    while (T--)
    {
        int n=read();
        unsigned long long ans=0;
        rep(i,1,(n-1)/2)
        {
            ans+=1ll*i*i*2*4;
        }
        printf("%llu\n",ans);
    }
    return 0;
}

D

用个堆维护当前的极长连续\(0\)区间即可。

struct node{int l,r;};
bool operator <(node p,node q)
{
    if (p.r-p.l!=q.r-q.l) return p.r-p.l<q.r-q.l;
    else return p.l>q.l;
}
priority_queue<node> q;
int n,a[200200];

int calc(int l,int r)
{
    if ((r-l+1)&1) return (l+r)>>1;
    else return (l+r-1)>>1;
}

int main()
{
    int T=read();
    while (T--)
    {
        n=read();
        q.push((node){1,n});
        int id=0;
        while (!q.empty())
        {
            node now=q.top();q.pop();
            int mid=calc(now.l,now.r);
            a[mid]=(++id);
            if (mid-1>=now.l) q.push((node){now.l,mid-1});
            if (mid+1<=now.r) q.push((node){mid+1,now.r});
        }
        rep(i,1,n) printf("%d ",a[i]);puts("");
    }
    return 0;
}

E

(可能做复杂了)

把所有模\(k\)的余数相同的位置拿出来,那么其它位置首先要变成\(0\).

记拿出来的权区间长度为\(n\),且有\(m\)\(1\),其前缀和为\(s_i\),枚举一下最后为1的区间\([l,r]\), 那么要求的就是\(\min(m-(s_r-s_{l-1})+(r-l+1)-(s_r-s_{l-1}))\), 即\(\min(m-2s_r+r+2s_{l-1}-(l-1))\).对后面哪个沿途取个\(\min\)即可,注意还要加上当前序列全为\(0\)时最优的情况。

int n,m,tot,k,a[1001000],s[1001000],all=0;
char str[1001000];

int calc(int md)
{
    m=0;tot=0;
    for (int i=md;i<=n;i+=k)
    {
        a[++tot]=(str[i]=='1');
        m+=a[tot];
    }
    rep(i,1,tot) s[i]=s[i-1]+a[i];
    int now=m,mx=0;
    rep(r,1,tot)
    {
        now=min(now,m-s[r]*2+r+mx);
        mx=min(mx,2*s[r]-r);
    }
    now+=all-m;
    return now;
}

int main()
{
    int T=read();
    while (T--)
    {
        n=read();k=read();
        scanf("%s",str+1);
        int ans=n;all=0;
        rep(i,1,n) all+=(str[i]=='1');
        rep(i,1,min(n,k)) ans=min(ans,calc(i));
        printf("%d\n",ans);
    }
    return 0;
}

F

一个显然的性质是如果\(a_{1,1}\)的值被确定了,那么沿途中每个位置的值都是确定的,即\(a_{i,j}=a_{1,1}+i+j-2\).

同时注意到如果最终的合法路径每个格子都被操作了至少一次,那么我们可以整体减少一次操作使其更优。

综合上面两个结论,就会发现最终\(a_{1,1}\)的取值只会有\(O(nm)\)个,枚举这个值然后跑dp就行了。

int n,m;
ll a[110][110],f[110][110];

ll work(ll st)
{
    rep(i,0,n) rep(j,0,m) f[i][j]=1e18;
    if (a[1][1]>=st) f[1][1]=a[1][1]-st;
    rep(i,1,n) rep(j,1,m)
    {
        if ((i==1) && (j==1)) continue;
        if (a[i][j]>=(st+i+j-2))
        {
            ll now=a[i][j]-(st+i+j-2);
            f[i][j]=min(f[i-1][j],f[i][j-1])+now;
        }
    }
    return f[n][m];
}

int main()
{
    int T=read();
    while (T--)
    {
        n=read();m=read();
        rep(i,1,n) rep(j,1,m) a[i][j]=readll();
        ll ans=4e18;
        rep(i,1,n) rep(j,1,m) ans=min(work(a[i][j]-(i+j-2)),ans);
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-05-15 01:16  EncodeTalker  阅读(148)  评论(0编辑  收藏  举报