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

来源:互联网 发布:淘宝发货后立即回款 编辑:程序博客网 时间:2024/06/05 16:02
  • 题目大意

    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 <iostream>#include <cstdio>#include <cstring>#include <math.h>#include <algorithm>#include <queue>using namespace std;#define LL long long intconst int MAXL=110;int num1[MAXL][40];//开头可以为0int num2[MAXL][40];//开头不能为0int 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]<ch[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;}/*31 1 2 361 982180 10 10496690841 524639270 5 20*/