题目
https://codeforces.com/contest/1120/problem/B
题目大意
给定两个长度都为n的数字串A和B,你可以执行若干次操作,每次操作是将相邻的两个位置+1或-1,要求不能对数字串以外的位置进行操作,且操作中每个数字都必须在[0,9]中。求把A变成B所执行的最小操作数,并输出前1e5个操作,无解输出-1。
2≤n≤1e5
题解
先求一遍最小操作数(其实就是不重复操作的操作数),然后模拟即可。
发现实际操作中若要
a
i
−
b
a_i-b
ai−b,且
a
i
−
b
<
0
a_i-b<0
ai−b<0,直接减去或先加上
b
−
a
i
b-a_i
b−ai的操作数是相等的(因为没有重复操作)。因此一开始直接不管限制模拟求出的操作数是正确的。
CODE
#include<cstdio>
using namespace std;
#define lim 100000
#define N 100005
long long ans,sum;
int n,s,a[N],b[N],c[N],d[N],tmp[N];
void add(int x,int y)
{
if(x==n||!y) return;
if(a[x+1]+y<0) add(x+1,-a[x+1]-y);
if(ans>=lim) return;
if(a[x+1]+y>9) add(x+1,9-a[x+1]-y);
if(ans>=lim) return;
a[x]+=y,a[x+1]+=y;
if(ans<=lim) c[++s]=x,d[s]=y;
ans+=y<0?-y:y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%1d",a+i),tmp[i]=a[i];
for(int i=1;i<=n;++i) scanf("%1d",b+i);
if(!b[1]){puts("-1");return 0;}
for(int i=1,j;i<n;++i)
if(tmp[i]!=b[i])
{
j=b[i]-tmp[i];
sum+=j>0?j:-j,tmp[i]+=j,tmp[i+1]+=j;
}
if(tmp[n]!=b[n]){puts("-1");return 0;}
for(int i=1;i<n;++i) if(ans<=lim) add(i,b[i]-a[i]);
printf("%lld\n",sum);
for(int i=1,cnt=0;i<=s;++i)
{
if(d[i]>0) while(d[i]&&cnt<lim) printf("%d 1\n",c[i]),--d[i],++cnt;
else while(d[i]&&cnt<lim) printf("%d -1\n",c[i]),++d[i],++cnt;
}
return 0;
}