POJ 1117

题意:给出一个n,求所有的x+y=n且y是x长度仅差1的子序列。

题解:分情况讨论,设y是x剔除第i位得到的数,

1)若i>lenth(n)/2,

y=x/10^i*10^(i-1)+x%10^(i-1)

=x/10^i*10(i-1)+x-x/10^(i-1)*10^(i-1)

=x-(x/10^(i-1)-x/10^i)*10^(i-1)

x+y=2x-(x/10^(i-1)-x/10^i)*10^(i-1)=n

设T=(x/10^(i-1)-x/10^i)

2x-T*10^(i-1)=n

x=(n+T*10^(i-1))/2

x,n,T均为整数且i>1,所以n非偶数直接返回,其他情况则枚举T直到x大于n,共需枚举约n/(10^(i-1))次。

2)其他情况

x+y=2x-(x/10^(i-1)-x/10^i)*10^(i-1)

其中x/10^i=(x-x%10^i)/10^i

所以原式=(11x-(x%10^i-x%10^(i-1)*10))/10=n

令M=(x%10^i-x%10^(i-1)*10

x=(10n+M)/11

同样,n,m,x均为整数,且m的范围是[-10^i,10^i],枚举所有使x有整数解的m。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 typedef long long LL;
  6 LL po[15];
  7 struct Data
  8 {
  9     LL x,y;
 10     bool operator<(const Data &ne)const
 11     {
 12         return x<ne.x;
 13     }
 14 }ans[10000];
 15 int top;
 16 LL remove(LL x,int i)
 17 {
 18     return x/po[i]*po[i-1]+x%po[i-1];
 19 }
 20 void solve1(int i,LL n)
 21 {
 22     LL left=-po[i],right=po[i],m=11-(10*n)%11,x;
 23     for(LL mm=m;mm>=left;mm-=11)
 24     {
 25         x=(10*n+mm)/11;
 26         if(x<=0ll)
 27             break;
 28         LL y=remove(x,i);
 29         if(x+y==n)
 30         {
 31             ans[top].x=x;
 32             ans[top++].y=y;
 33         }
 34     }
 35     for(LL mm=m+11;mm<=right;mm+=11)
 36     {
 37         x=(10*n+mm)/11;
 38         if(x>=n)
 39             break;
 40         LL y=remove(x,i);
 41         if(x+y==n)
 42         {
 43             ans[top].x=x;
 44             ans[top++].y=y;
 45         }
 46     }
 47 }
 48 void solve2(int i,LL n)
 49 {
 50     if(n%2!=0)
 51         return;
 52     LL ad=po[i-1]/2;
 53     for(LL x=n/2+ad;x<=n;x+=ad)
 54     {
 55         LL y=remove(x,i);
 56         if(x+y==n)
 57         {
 58             ans[top].x=x;
 59             ans[top++].y=y;
 60         }
 61     }
 62 }
 63 int main()
 64 {
 65     LL n;
 66     po[0]=1;
 67     for(int i=1;i<=10;i++)
 68         po[i]=po[i-1]*10ll;
 69     while(scanf("%lld",&n)!=EOF)
 70     {
 71         top=0;
 72         int len;
 73         for(len=1;len<=10;len++)
 74             if(n<po[len])
 75                 break;
 76         for(int i=1;i<=len/2;i++)
 77             solve1(i,n);
 78         for(int i=len/2+1;i<=len;i++)
 79             solve2(i,n);
 80         if(top==0)
 81         {
 82             printf("0\n");
 83             continue;
 84         }
 85         sort(ans,ans+top);
 86         int num=0;
 87         for(int i=1;i<top;i++)
 88         {
 89             if(ans[i].x!=ans[num].x)
 90                 ans[++num]=ans[i];
 91         }
 92         num++;
 93         printf("%d\n",num);
 94         for(int i=0,j,k;i<num;i++)
 95         {
 96             for(j=1;j<=10;j++)
 97                 if(ans[i].x<po[j])
 98                     break;
 99             for(k=1;k<=10;k++)
100                 if(ans[i].y<po[k])
101                     break;
102             printf("%lld + ",ans[i].x);
103             k++;
104             while(k<j)
105                 printf("0"),k++;
106             printf("%lld = %lld\n",ans[i].y,n);
107         }
108     }
109     return 0;
110 }

转载于:https://www.cnblogs.com/tmeteorj/archive/2012/10/06/2713341.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值