• pongo英雄会-幸运数题解


    显然我们只要知道1~x范围有多少幸运数(用f(x)表示),lucky(x,y)=f(y)-f(x-1).

    解法1. 计算排列数

    由于y<=1000000000这个规模,我们不能暴力验证每个数是否是幸运数。可以想到,对于同样的数字组成,不同的数字排列对应不同的幸运数,比如12,21。那么就只需枚举合法的数字组成,算出相应的排列数。设数字i有a[i]个,n=Σa[i],则对应的排列数是n!/∏a[i]!。

    接下来就只要枚举那些合法的数字组成了。我们希望枚举时对每位的可取数字是没有限制的,可以分类来进行。下面举例说明。

    比如x=2345. 当千位是0或1时,后三位是没有限制的,0~9都可以,可以用递归来枚举a[i],然后结合已确定的千位来判断这种组成是否是幸运数,是的话答案就加上相应的排列数。

    当千位等于2时,继续依次固定百位=0,1,2计算。余此类推。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<time.h>
    using namespace std;
    
    bool isPrime(int n)
    {
        if(n<2)  return false;
        int i;
        for(i=2;i*i<=n;i++) if(n%i==0) return false;
        return true;
    }
    
    bool check(int cnt[],int n1,int n2)
    {
        int i;
        int s1=n1,s2=n2;
        for(i=1;i<10;i++)
        {
            s1+=i*cnt[i];
            s2+=i*i*cnt[i];
        }
        return isPrime(s1)&&isPrime(s2);
    }
    
    int fac[10];
    void comFactorial()
    {
        int i;
        fac[0]=1;
        for(i=1;i<10;i++) fac[i]=fac[i-1]*i;
    }
    
    int nPermutation(int cnt[])
    {
        int i;
        int n=0;
        for(i=0;i<10;i++) n+=cnt[i];
        int ans=fac[n];
        for(i=0;i<10;i++) ans/=fac[cnt[i]];
        return ans;
    }
    
    void dfs(int digit,int n,int cnt[],int n1,int n2,int &ans)
    {
        int i;
        if(digit==10)
        {
            cnt[0]=n;
            if(check(cnt,n1,n2))
            ans+=nPermutation(cnt);
            return ;
        }
        for(i=0;i<=n;i++)
        {
            cnt[digit]=i;
            dfs(digit+1,n-i,cnt,n1,n2,ans);
        }
    }
    
    int com(int x)
    {
        comFactorial();
        int digit[12];
        int cnt[12];
        int i,j,n=0;
        while(x>0)
        {
            digit[n++]=x%10;
            x/=10;
        }
        int n1=0,n2=0,s1,s2,ans=0;
        for(i=n-1;i>0;i--)
        {
            for(j=0;j<digit[i];j++)
            {
                s1=n1+j;
                s2=n2+j*j;
                dfs(1,i,cnt,s1,s2,ans);
            }
            n1+=digit[i];
            n2+=digit[i]*digit[i];
        }
        for(i=0;i<=digit[0];i++)
        {
            s1=n1+i;
            s2=n2+i*i;
            if(isPrime(s1)&&isPrime(s2)) ans++;
        }
        return ans;
    }
    
    int lucky(int x,int y)
    {
        return com(y)-com(x-1);
    }
    

      

    解法2. dp

    dp[n][s1][s2]表示n位,各位数字的和为s1,平方和为s2的方法数。根据第一位的数字来状态转移,dp[n][s1][s2]=Σdp[n-1][s1-i][s2-i*i] i=0...9

    两种方法的共同之处是都要逐渐固定高位来分类计算。

    #include <cstring>
    #include <vector>
    #include <iostream>
    #include <set>
    #include <map>
    #include <algorithm>
    #include<deque>
    #include<cstdio>
    #include<time.h>
    using namespace std;
    
    int dp[12][82][730];
    
    bool isPrime(int n)
    {
        int i;
        if(n<2) return false;
        for(i=2;i*i<=n;i++) if(n%i==0) return false;
        return true;
    }
    
    
    int f(int n,int s1,int s2)
    {
        if(dp[n][s1][s2]!=-1) return dp[n][s1][s2];
        if(n==1)
        {
            if(s1<10&&s1*s1==s2) return dp[n][s1][s2]=1;
            else return dp[n][s1][s2]=0;
        }
        else
        {
            int i;
            int ans=0;
            for(i=0;i<10&&i<=s1&&i*i<=s2;i++) ans+=f(n-1,s1-i,s2-i*i);
            return dp[n][s1][s2]=ans;
        }
    }
    
    int com(int x)
    {
        int a[20];
        int num=0;
        while(x>0)
        {
            a[num++]=x%10;
            x/=10;
        }
        int ans=0;
        int i,j,k,m;
        int s1=0,s2=0;
        int p1=0,p2=0;
        for(k=num-1;k>0;k--)
        {
            for(m=0;m<a[k];m++)
            {
                s1=p1+m;
                s2=p2+m*m;
        for(i=0;i<=9*k;i++)
         for(j=i;j<=81*k;j++)
         {
             if(isPrime(i+s1)&&isPrime(j+s2))
             ans+=f(k,i,j);
         }
            }
            p1+=a[k];
            p2+=a[k]*a[k];
        }
        for(i=0;i<=a[0];i++)
        if(isPrime(p1+i)&&isPrime(i*i+p2)) ans++;
        return ans;
    }
    
    int lucky(int x,int y)
    {
        memset(dp,-1,sizeof(dp));
        return com(y)-com(x-1);
    }
    

      

    转自 http://blog.csdn.net/shuyechengying/article/details/9164517

     
  • 相关阅读:
    kubuntu设置
    odoo git环境搭建
    ubuntu Gnome 14.10添加打印机
    ubuntu 14.10安装Balsamiq Mockups
    elementary os luna安装配置
    OpenERP QWeb模板标签笔记
    pycharm3 注册码
    统计项目代码
    odoo filter 日期
    opencart 安装
  • 原文地址:https://www.cnblogs.com/downtjs/p/3197899.html
Copyright © 2020-2023  润新知