2021icpc沈阳 J

题意:

给出一个四位数字字符串,可以对其中任意长度的区间同时+1或-1,其中9+1会变成0,0-1会变成9,并且给出四位目标字符串,求变成目标字符串的最小操作次数

Solution:

没有想法就搜索,就4位,爆搜都是接近O(1)O(1)O(1)的复杂度,不妨将四位分成若干组,然后对每组求最小次数,然后合并答案,取最优答案。有如下这么多分组

vector<vector<int>>vv={
    {1,1,1,1},
    {1,1,2},
    {1,2,1},
    {1,3},
    {2,1,1},
    {2,2},
    {3,1},
    {4}
};

对每一组,要么同时+1,要么同时-1才是最快的,这样的操作就转化成了经典例题(洛谷P5019),只需要求+1的次数和-1的次数取最小即可,需要注意的是,如果某一位已经和目标字符一样了,它可以有两种情况的操作次数{0,10}\{0,10\}{0,10},而非{0,0}\{0,0\}{0,0}

// #include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;

using ll=long long;
const int N=100005,inf=0x3fffffff;
const long long INF=0x3f3f3f3f3f3f,mod=998244353;

bool vis[20];
vector<vector<int>>vv={
    {1,1,1,1},
    {1,1,2},
    {1,2,1},
    {1,3},
    {2,1,1},
    {2,2},
    {3,1},
    {4}
};
char s[20],t[20];
int add[20],del[20];

int solve(int l,int r)
{
    int ret=inf;
    for(int i=l;i<=r;i++)
    {
        if(t[i]<=s[i]) add[i]=t[i]+10-s[i];
        else add[i]=t[i]-s[i];
        if(t[i]>=s[i]) del[i]=s[i]+10-t[i];
        else del[i]=s[i]-t[i];
    }
    int tot1=0,tot2=0;
    add[r+1]=del[r+1]=0;
    for(int i=r;i>=l;i--)
    {
        if(s[i]==t[i])
        {
            if((add[i]>add[i+1])*(add[i]-add[i+1])+(add[i-1]>add[i]&&i>l)*(add[i-1]-add[i])>(0>add[i+1])*(0-add[i+1])+(add[i-1]>0&&i>l)*(add[i-1]-0)) add[i]=0;
            if((del[i]>del[i+1])*(del[i]-del[i+1])+(del[i-1]>del[i]&&i>l)*(del[i-1]-del[i])>(0>del[i+1])*(0-del[i+1])+(del[i-1]>0&&i>l)*(del[i-1]-0)) del[i]=0;
        }
        tot1+=(add[i]>add[i+1])*(add[i]-add[i+1]);
        tot2+=(del[i]>del[i+1])*(del[i]-del[i+1]);
    }
    return min(tot1,tot2);
}

void work()
{
    scanf("%s%s",s+1,t+1);
    int ans=inf;
    for(auto& sub:vv)
    {
        int done=0,tot=0;
        for(auto& i:sub)
        {
            tot+=solve(done+1,done+i);
            done+=i;
        }
        ans=min(ans,tot);
    }
    printf("%d\n",ans);
}

int main()
{
    int t; cin>>t;
    while(t--) work();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值