HDU 6156 Palindrome Function(数位 回文串 17CCPC网络赛)

  • 题目大意

    f(n,k)={k1nk

    让你求
    i=LRj=lrf(i,j)

  • 分析

    这道题可以将问题简化成求:

    给你一个数n(十进制),问你在k进制下不超过n的回文数有多少个

    这道题我的做法有点冗余了,改了好久找了一份AC代码对拍才改过的。

    设n在k进制下长度为m,用数组表示为 a[1...len] 先分类:

    1. 长度小于m的回文数的个数,这个比较好求,初始化以下就行
    2. 长度等于m的回文数的个数,又分为两类
      1.首位元素小于 a[1]
      2.首位元素为 a[1]

    定义了一个函数Less(int ch[],int len,int k),ch[]用来保存k进制下的数
    定义 num1[m][k] 表示长为m在k进制下的回文数的个数,开头可以是0
    定义 num1[m][k] 表示长为m在k进制下的回文数的个数,开头不能是0
    这个函数表示小于长为len小于等于ch的数的个数(需要注意的是这里的数可以是以0开头的)

    由于Less找的是可以以0开头的数,所以在最外层中还要减去开头是0的情况数也就是 num[len2][k]

    需要处理边界条件是len为0 1 2 的情况

  • 总结
    像这样的题,以后一定要多想想有没有简单一点的实现方式

  • 代码

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define LL long long int
const int MAXL=110;
int num1[MAXL][40];//开头可以为0
int num2[MAXL][40];//开头不能为0
int Pow(int n,int k)
{
    int ans=1;
    for(int i=1;i<=k;i++)ans*=n;
    return ans;
}
void Make_num1()
{
    for (int i=1;i<=100;i++)
        for (int j=2;j<=36;j++)
        {
            if (i==1) num1[i][j]=j;
            else num1[i][j]=Pow(j,(i+1)/2);
        }
}
void Make_num2()
{
    for (int i=1;i<=100;i++)
        for (int j=2;j<=36;j++)
        {
            if (i==1) num2[i][j]=j;
            else num2[i][j]=(j-1)*Pow(j,(i-1)/2);
        }
}
int Make_ch(int ch[],int n,int k)///把1个十进制的数转换成k进制
{
    int len=0;
    while (n)
    {
        ch[++len]=n%k;
        n/=k;
    }
    return len;
}
bool is_Palindrome(int ch[],int len)
{
    bool flag=true;
    for (int i=1;i<=len/2;i++)
        if (ch[i]!=ch[len-i+1])
        {
            flag=false;
            break;
        }
    return flag;
}
int Less(int ch[],int len,int k)//k进制下不超过n首可以为0的个数
{
    int res=0;
    if (len==0) return 1;
    if (len==1) return (ch[len]+1);
    if (len==2)
    {
        if(ch[len]<=ch[1])return ch[len]+1;
        else return ch[len];
    }
    ///长度等于len且第一位比当前小的回文数     边界
    res+=(ch[len]*num1[len-2][k]);
    ///长度等于len且第一位等于当前第一位的回文数
    int p=0;
    int temp[MAXL];int len2=0;
    for (int i=2;i<=len-1;i++)
    {
        temp[++len2]=ch[i];
        p+=ch[i]*Pow(k,len2-1);
    }
    res+=Less(temp,len2,k);
    if (ch[1]len]&&is_Palindrome(temp,len2))
       res--;
    return res;
}
int Work(int n,int k)
{
    int ans=0;
    int ch[MAXL];
    int len=Make_ch(ch,n,k);
    if (len==0) return 1;
    if (len==1) return (ch[1]+1);
    if (len==2)
    {
        if(ch[len]<=ch[1])return ch[len]+k;
        else return ch[len]-1+k;
    }
    ans=Less(ch,len,k);
    for (int i=0;i<len;i++) ans+=num2[i][k];///长度小于len的回文数
    ans-=num1[len-2][k];//Less(p,k);
    return ans;
}
int main()
{
    //freopen("data.txt","r",stdin);
    //freopen("out1.txt","w",stdout);
    Make_num1();
    Make_num2();
    int T,L,R,l,r,j,cnt=0;
    LL ans=0;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d%d",&L,&R,&l,&r);
        ans=0;
        for (j=l;j<=r;j++)
        {
            int x=Work(R,j)-Work(L-1,j);
            int sum=R-L+1;
            ans+=(x*j+sum-x);
        }
        printf("Case #%d: %lld\n",++cnt,ans);
    }
    return 0;
}
/*
3
1 1 2 36
1 982180 10 10
496690841 524639270 5 20
*/

你可能感兴趣的:(HDU 6156 Palindrome Function(数位 回文串 17CCPC网络赛))