【百度之星初赛2】魔法因子|乘某个数首末位互换(数学,灵活题)

91 篇文章 1 订阅
15 篇文章 0 订阅

有人说:人类是自己一步步进化的,而数学是上帝亲手创造的。度度熊最近也正沉醉于数学之美中,它发现了一种神奇的数字,取名曰:魔法因子。

将因子记为X,如果有一些整数与这些因子做乘法后,结果仍然是整数,同时,结果数字的首位和末位会换交换位置,而其他位置上的数字恰好不变!这时X被认为是一个魔法因子。需要注意的是,用来相乘的这些整数不会含有前导0,但是如果交换的结果有前导0,又恰好是乘法的结果,这时仍然认为X是这个整数的魔法因子。度度熊认为1不是个魔法因子,因为所有的数都可以符合这个条件,这一点都不好玩。

比如,X = 3.1312,有1875 * 3.1312 = 5871。

度度熊现在希望知道对于一个因子X,究竟有多少个整数可以满足这个条件,使其成为魔法因子。由于它还不会长度超过10位数的乘法,只需要求出长度不超过10的整数即可。
 

Input
第一行一个整数T,表示包含T组数据。
每组数据包含一个实数 X(0<X<10,X1) ,同时为了避免精度问题,小数点后的数字不会超过6位。
 

Output
每组数据,对于每组数据,先输出一行

Case #i:

然后输出符合条件的整数的个数,如果个数不为0,在第二行输出所有符合条件的整数,按数字大小升序排列,用空格隔开,如果个数为0,只输出一行。
 

Sample Input
  
  
3 3.1312 3.1415 0.3
 

Sample Output
  
  
Case #1: 3 1875 1876875 1876876875 Case #2: 0 Case #3: 2 1428570 2857140

http://acm.hdu.edu.cn/showproblem.php?pid=5255

思路:设符合条件的数的最高位是h,最低位是l,中间不变的部分为mid,由题意可得到下面的公式(这里对X乘上1e6用a表示,b表示1e6)
(h*power+l+mid)*a=(l*power+h+mid)*b
可推得:mid=((h*power+l)*a-(l*power+h)*b)/(a-b);
所以可以枚举h,l然后求mid,注意mid的最低位一定是0,因为留出最低位加l或者h  (转载)

这里要注意一点:把小数乘10^n化成整数这一步是必不可少的,因为后面mid是longlong还有取余都是要用到整数的。

p=round(x*MG),g=__gcd(p,MG) ,round()是四舍五入。

#include<iostream>  
#include<algorithm>  
#include<string>  
#include<map>  
#include<vector>  
#include<cmath>  
#include<queue>  
#include<string.h>  
#include<stdlib.h>  
#include<stdio.h>
#define eps 1e-6
#define ll long long  
using namespace std;
ll pw[15];
vector<ll> x;
void init()  
{  
    pw[0]=1;
    for(int i=1;i<12;i++)  
        pw[i]=pw[i-1]*10;  
}  
int main(){
    init();
    int t;
    scanf("%d",&t);
    int cntt=0;
    while(t--){
        x.clear();
        double w;
        scanf("%lf",&w);
        ll n=w*pw[6]+eps;  //这里+eps必不可少 
        for(int k=2;k<=10;++k){   //k是这个数的长度 
            for(int i=1;i<=9;++i){      //首 
                for(int j=0;j<=9;++j){  //尾   
                    ll mid=(pw[k-1]*j+i)*pw[6]-(pw[k-1]*i+j)*n;
                    if(mid%(10*(n-pw[6]))==0){  //注意*10 
                        mid/=(n-pw[6]);
                        if(mid<0)      //这里要特别注意!mid是有可能小于0的!! 
                            continue;
                        int cnt=0;
                        ll q=mid;
                        while(q){
                            cnt++;
                            q/=10;
                        }
                        if(cnt<=k-1)
                            x.push_back(i*pw[k-1]+mid+j);
                    }
                }
            }
        }
        printf("Case #%d:\n",++cntt);  
        printf("%d\n",x.size());  
        if(x.size()==0)  
            continue;
        for(int i=0;i<x.size()-1;++i)
            cout<<x[i]<<" ";
        cout<<x[x.size()-1]<<endl;
    }
    return 0;
} 

#include<iostream>    
#include<algorithm>    
#include<string>    
#include<map>    
#include<vector>    
#include<cmath>    
#include<queue>    
#include<string.h>    
#include<stdlib.h>    
#include<stdio.h>  
#define ll long long 
#define N (1<<4)
#define MG 1000000ll   
using namespace std;  
double x;
int T,cas;
ll pw[N]={1};
vector<ll> res;

void init()
{
    for(int i=1;i<12;i++)
        pw[i]=pw[i-1]*10;
}

bool judge(ll x,ll y,int n)
{
    if(x<pw[n] || x>=pw[n+1]) return 0;
    ll a=x/pw[n],b=x%10,c=x-a*pw[n]-b;
    return y==b*pw[n]+c+a;
}

int main()
{
    init();
    for(cin>>T;T--;)
    {
        res.clear();
        scanf("%lf",&x);
        ll p=round(x*MG),g=__gcd(p,MG),q=MG/g; p/=g;  //round四舍五入 

        for(int i=1;i<=9;i++)
            for(int j=-9;j<=9;j++)
                if((pw[i]*j-j)%(q-p)==0)
                {
                    ll t=(pw[i]*j-j)/(q-p);
                    if(judge(t*q,t*p,i))  //这里就是直接反转,判断
                        res.push_back(t*q);
                }

        sort(res.begin(),res.end());

        printf("Case #%d:\n%d\n",++cas,res.size());
        if(res.size())
        {
            for(int i=0;i<res.size()-1;i++)
                printf("%I64d ",res[i]);
            printf("%I64d\n",*(res.rbegin()));
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值