2016CCPC长春站 J 题意 思路 程序
将一个长度不超过(1000)的大整数拆分成不超过(50)个回文数之和。
思路
每次考虑从数(a)中拆分出一个最大的回文数(b)
从高位开始向中位循环,把(b)中对称的一对位置的数字定作数(a)中对应位置的数字
例如(a=54321),每个对称位置取大,得到初始的(b=54345)
例如(a=1716999),得到(b=1716171)
然后判断两个数的大小,如果满足(aleq b),那么(b)就可以作为这个回文数,同时将(a)减去(b)
如果(agt b),那么需要从数(b)的中部考虑将某个数位减去(1)
因为数字(a)与(b)的左半部分相同,如果(b)在左半部分任意减去一个(1)(假如能减),肯定可以保证(alt b)成立
所以从中位开始向高位循环,如果当前位不为(0)且不是最高位(会出现前导(0)),则将当前位与对称的位同时减(1)(保证回文);或者如果当前位是最高位,且大于(1),也可以减去
例如在(a=54321)的情况,初步得到(b=54345),发现中位(3ge 0),故最终(b=54245)
例如在(a=11000)的情况,初步得到(b=11011),发现次高位(1ge 0),故最终(b=10001)
但如果在最高位为(1),其余位均为(0)的情况下(即样例),那么可以发现最大的回文数为位数(-1)后全为(9)的数字
例如在(a=10000)的情况下,初步得到(b=10001),发现没有任何一位可以被减,故最终(b=9999)
最后,手写下大数减法、大数判断即可。
程序
代码里将数字倒着存了,然后用了变量(len)来控制当前处理的数字(a)的位数
每次进行减法之后就更新一次(len)
#include<bits/stdc++.h>
using namespace std;
int a[1050],b[1050];
int len;
vector<int> v[55];
bool check() //判断a是否回文
{
for(int i=0,j=len-1;i<=j;i++,j--)
if(a[i]!=a[j])
return false;
return true;
}
bool check2() //判断a>=b
{
for(int i=len-1;i>=0;i--)
if(b[i]>a[i])
return false;
else if(b[i]<a[i])
return true;
return true;
}
void subtract() //将a=a-b,并更新len
{
for(int i=0;i<len;i++)
{
if(a[i]<b[i])
{
a[i]+=10;
a[i+1]-=1;
}
a[i]-=b[i];
}
while(len>0&&a[len-1]==0)
len--;
}
void deal(int pos)
{
if(check()) //如果是回文,直接结束
{
v[pos].clear();
for(int i=len-1;i>=0;i--)
v[pos].push_back(a[i]);
len=0;
return;
}
for(int i=0,j=len-1;i<=j;i++,j--) //初步处理出数字b
{
b[i]=b[j]=a[j];
}
if(check2()) //如果a>=b,直接将b作为答案并a=a-b
{
v[pos].clear();
int i=len-1;
while(i>0&&b[i]==0)
i--;
for(;i>=0;i--)
v[pos].push_back(b[i]);
subtract();
}
else
{
bool flag=false;
for(int i=len/2,j=len/2-(len%2==0?1:0);j>=0;i++,j--)
{
if(b[i]>0&&j>0||b[i]>1&&j==0) //尝试做某一位的减法
{
b[i]--;
if(i!=j)
b[j]--;
flag=true;
break;
}
}
if(flag) //做了减法,此时可以直接a=a-b
{
v[pos].clear();
int i=len-1;
while(i>0&&b[i]==0)
i--;
for(;i>=0;i--)
v[pos].push_back(b[i]);
subtract();
}
else //否则,将b作为a位数-1后全为9的数
{
v[pos].clear();
for(int i=0;i<len-1;i++)
b[i]=9,v[pos].push_back(9);
b[len-1]=0;
subtract();
}
}
}
void solve(int cas)
{
string str;
cin>>str;
len=str.size();
for(int i=0;i<len;i++)
a[i]=str[len-i-1]-'0';
int t=0;
while(len>0) //如果a的长度不为0,继续处理下去
deal(t++);
cout<<t<<'
';
for(int i=0;i<t;i++)
{
for(int it:v[i])
cout<<it;
cout<<'
';
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;cin>>T;
for(int t=1;t<=T;t++)
{
cout<<"Case #"<<t<<":
";
solve(t);
}
return 0;
}