cf#342-D - Finals in arithmetic-构造

http://codeforces.com/contest/625/problem/D

题意:

给你一个数字字符串s,长度1e6,算是一个大数吧,让你找到一个x,使得,x加上  逆转(x)=s


例如33,能找到 12,逆转(12)=21

12+21=33

输出的x不允许有前导零,例如输出 032是错的,只能输出32,如果输出320,她的逆转是023,他们的和是320+23

其实,X和逆转X就是一对回文串啦

一开始单纯地以为是回文串啦,其实还要考虑进位的问题

如 87+78 =165 ,7+8后会进位


总得来说,我们就是要把长度为n位的一个串拆成两个长度n位的回文串

我们要尽可能让 S 的第i位和第n-1-i位相同,只有这两位相同,才可能分解出两个一样的数字构成回文串

我们令l=头,r=尾

逐个比较, 如果 s[l]==s[r] ,则l,r向中间移动一格,

否则,我们看能否通过进位使得他们相等, 对于l,它左边是已经确定的,就别动了,只考虑l的往右退位

同样,对于r,它的右边是确定的,只考虑r-1位的退位

也就是三种情况:

1、  左边l退位,  if ( s[l] -1 == s[r] )

     2、右边r-1退位,r增10   if (s[l] == s[r]+10 )

    3、左右同时退位       if ( s[l]-1 == s[r] +10 )

 如果满足哪种情况 则作相应操作,如果都不满足 则必然不可能构造出一个X  

 要注意的是  当r-l==1的时候, 情况1不可能成立,也就是不只左边往右退位,而右边不进位,情况3同理


判断完整个串后,还要考虑奇偶,如果是偶数长度必然没问题,如果是奇数长度,要看 最中间的那个位的数,是否为偶数,如果为奇数,则无法分解成2个回文串


至此,对于其余的位,只需要 靠左的第i位 构造为 (S【i】+1/)2,右边第n-1-i为s【i】/2

前导零的问题:

        //我们求答案的过程0abc,cba0,这种情况是合法的,但是我们要输出cba0

//我们已经尽量让奇数的一边在前面了,如果得到的答案还有前导零,表明答案是,0ab0,的情况,这种情况两个数都有前导零,显然也不合法 


------------以上的构造基于,长度为n位的一个串拆成两个长度n位的回文串

还有一种情况,长度为n位的穿 是由长度 n-1的回文串构造而成

如 78+87=165 ,这时我们要特判一下

即,先把 首位1,加到第二位,变成(16)(5)

然后再按照上面的方法再判断一次, 注意第一次的判断已经改变了子串的数字,需要copy一下备份

参考代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const __int64 inf=2147483647;
const double pi=acos(-1.0);
double eps=0.000001;
__int64 min(__int64 a,__int64 b)
{return a<b?a:b;}
__int64 max(__int64 a,__int64 b)
{
	return a<b?b:a;
}  

int ans[200000+5];
char tm[200000+5]; 
int num[200000+5]; 
int check(int *t,int len)
{
 
	 int i;
	for (i=0;i<=len/2;i++)
	{
		int l=i;
		int r=len-1-i;
		if (t[l]==t[r]) continue;
		else
			if (t[l]-1==t[r]&&r-l!=1)	///注意相邻的时候不能只左边往右退位,而右边不进位
			{
				t[l]--;
				t[l+1]+=10;
			}
			else
				if(t[l]-1==t[r]+10)
				{
					t[l]--;
					t[l+1]+=10;
					if (r-l==1)continue;
					t[r]+=10;
					t[r-1]--;
				}
				else if (t[l]==t[r]+10&& r-l!=1)	//注意相邻
				{
					t[r]+=10;
					t[r-1]--;
				}
				else
					return 0;
	}	 
	if (len%2)
	{
		if (  t[len/2]%2 || t[len/2]>18 || t[len/2]<0 ) return 0;
		ans[len/2]=t[len/2]/2;
	}
	for (i=0;i<len/2;i++)
	{
		if (t[i]>18 || t[i]<0  ) return 0;
		ans[i]=(t[i]+1)/2;
		ans[len-i-1]=t[i]/2;
	}
	return ans[0]>0 ;
	//我们求答案的过程0abc,cba0,这种情况是合法的,但是我们要输出cba0
	//我们已经尽量让奇数的一bian在前面了,如果得到的答案还有前导零,表明答案是,0ab0,的情况,这种情况两个数都有前导零,显然不合法 
}


int main()
{
	int i,j,k; 
	scanf("%s",tm+1);
		int len=strlen(tm+1); 
	for (i=1;i<=len;i++)
		num[i]=tm[i]-'0';
	
	int flag=0;
	if (check(num+1,len))
		flag=1;
	if (flag)			//第一次判断成功,分解为2个长度len的回文串
	{
		for (i=0;i<len;i++)
			printf("%d",ans[i]);
		printf("\n");
	}	
	else			//第一次判断失败
	{
			for (i=1;i<=len;i++)		//恢复原字符串
			num[i]=tm[i]-'0';
		if (num[1]==1)				//首位是1,有可能是由长度len-1的两个回文串相加而成,特判
		{
			
			num[2]+=10;					
			if (check(num+2,len-1))
			flag=1;
			if (flag)
			{
				for (i=0;i<len-1;i++)
					printf("%d",ans[i]);
				printf("\n");
			}
			else
				printf("0\n"); 
		}
		else
		printf("0\n");
	}
	 
	
	return 0;
	
} 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 你可以在 CSDN 上创建一个项目,然后将文件上传到该项目中。具体步骤是:登录 CSDN,进入个人中心,点击“我的项目”,然后点击“创建项目”,填写项目信息,选择“上传文件”,将文件上传到项目中即可。如果你遇到了问题,可以在 CSDN 的帮助中心中查找相关的教程或者向客服咨询。 ### 回答2: 要上传文件到“finals hell”,您可以按照以下步骤操作: 1. 首先,打开您的电脑,并连接到互联网。 2. 打开您的网页浏览器,并键入“finalshell.com”。然后按下“Enter”键,访问“finals hell”网站。 3. 如果您还没有账户,请先注册一个新的账户。您需要提供有效的电子邮件地址和创建一个安全的密码。完成填写后,按照账户创建的指引完成注册。 4. 注册完成后,使用您的电子邮件地址和密码登录到“finals hell”账户。 5. 在登录后的页面上,您将找到一个“上传文件”或类似的选项。通常,它会显示为一个按钮或一个图标。 6. 单击“上传文件”选项,这将打开一个文件浏览器对话框。 7. 在文件浏览器对话框中,浏览并选择您要上传的文件。您可以通过双击文件或者选择文件后点击“打开”按钮来选取文件。 8. 一旦您选择了文件,等待上传完成。此过程的时间取决于文件大小和您的互联网连接速度。 9. 上传完成后,您将收到通知或者文件会在页面上显示。您现在可以将该文件与其他人共享或者进行其他相关操作。 10. 完成后,您可以继续上传其他文件或者退出“finals hell”账户。 请注意,以上步骤仅为基本指导。根据具体情况,界面和操作可能会略有不同。对于更详细的指导,请参考“finals hell”网站上的帮助文档或联系他们的客户支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值