Codeforces 1120B Once in a casino

题目

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 aib,且 a i − b < 0 a_i-b<0 aib<0,直接减去或先加上 b − a i b-a_i bai的操作数是相等的(因为没有重复操作)。因此一开始直接不管限制模拟求出的操作数是正确的。

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;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/108652502