HDOJ 1554 Pairs of integers

题目大意是:

给定一个数N(10 ……10^9),求出A,B,A的开头数字不能为0,B的开头数字可以为0,B为A去掉一个10进制位后得到的数字

及A的数位一定是B的数位+1,并且A + B = N


我们可以遍历,去掉A的第pre位后得到B,

我们假设pre位前面的为x,pre位为y,pre位后为z

即A 为 xyz,那么B为xz

这个时候y的权为flag = 10^pre

因为A + B = N

所以xy * flag  + x * flag + 2 * z = N

所以一定满足(N - 2 * z)% flag == 0;(对z的遍历初始化z = (N - N / flag* flag) / 2,并每次z+=flag/2,可以保证这个条件成立并使算法复杂度降到很低,注意当N为奇数时

该条件基本上不成立,但是当flag = 1及去掉的就是各位的时候可以成立)


并且x,y中至少有一个不为0,所以(N - 2 * z) >= flag;

并且N - 2 * z >0;

并且z是比权flag要小的

并且因为y是要被去掉的数字,所以y一定不能大于10

因为xy * flag  + x * flag + 2 * z = N         =》      x = (N - 2 * z) / 11;   Y = (N - 2 * z) % 11;


根据以上的这些条件就可以算出所有符合条件的A,B

但还是要注意结果中有重复的比如12 = 11 + 1;可以从11中去掉十位得到1,还可以从11中去掉各位得到1

所以结果中有重复,需去重

结合我的代码再次分析

我的代码:

#include<stdio.h>

int stack[1001];
int snum;

int add(int x, int y, int z, int pre)//xyz即为答案,注意z的位数为pre-1
{
	int i, array[11];
	
	array[pre] = y;              //y是确定的第pre为
	for(i = 1; i < pre; i ++)    //z是pre后面的数字
	{
		array[i] = z % 10;
		z /= 10;
	}
	for(i = pre + 1; i <= 10; i ++)//
	{
		array[i] = x % 10;
		x /= 10;
	}
	
	stack[++ snum] = 0;          //算出结果存如栈中
	for(i = 10; i >= 1; i --)
	{
		stack[snum] *= 10;
		stack[snum] += array[i];
	}
	
	return 0;
}

int Max(int a, int b)
{
	return a > b ? a : b;
}

int find(int pre, int n)
{
	int i;
	int flag = 1;
	int max;
	
	if(pre == 0)
		return 0;
	
	for(i = 1; i < pre; i ++)     //算出权值
		flag *= 10;
	
	if(pre != 1 && n % 2 == 0 || pre == 1)//只有当flag = 1和n不为奇数的时候才能保证(N - 2 * z)% flag == 0;
	{
		max = Max(flag / 2, 1);
		for(i = (n - n / flag * flag) / 2; i < flag; i += max)//在(N - 2 * z)% flag == 0的前提下,只有z+=flag*2才能继续满足条件
		{
			if(i * 2 >= n)
				break;
			if((n - i * 2) < flag)
				break;
			if((n - i * 2) / flag % 11 != 10)
			{
				add((n - i * 2) / flag / 11, (n - i * 2) / flag % 11, i, pre);//算出了x,y,z,加入栈
			}
		}
	}
	
	return find(pre - 1, n);
}

int swap(int &a, int &b)
{
	a ^= b;
	b ^= a;
	a ^= b;
	return 0;
}

int sort()
{
	int i, j;

	for(i = 1; i < snum; i ++)
		for(j = i + 1; j <= snum; j ++)
		{
			if(stack[i] == stack[j])//存在相同答案就去掉相同答案
			{
				stack[j] = stack[snum];
				snum --;
				j --;
			}
		}

	for(i = 1; i <= snum; i ++)          //排序
	{
		for(j = i + 1; j <= snum; j ++)
		{
			if(stack[i] > stack[j])
			{
				swap(stack[i], stack[j]);
			}
		}
	}
	return 0;
}

int prin(int x, int n)
{
	int y = n - x, i;       //由A算出B,但是B的位数一定要有A的位数-1,否则前面补0
	int array[11], tail = 0;
	printf("%d + ", x);
	while(x >= 10)
	{
		array[++ tail] = y % 10;
		y /= 10;
		x /= 10;
	}
	for(i = tail; i >= 1; i --)
		printf("%d", array[i]);
	printf(" = %d\n", n);
	
	return 0;
}

int main()
{
	int n;
	int i;
	while(scanf("%d", &n) != EOF)
	{
		snum = 0;
		find(10, n);    //从去掉第10为开始找
		sort();

		printf("%d\n", snum);    //坑爹的地方,因为总数没输出导致我一直wa,调试了好久,唉
		
		for(i = 1; i <= snum; i ++)
		{
			prin(stack[i], n);
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值