Hdu 6156 Palindrome Function 2017 CCPC网络赛

来源:互联网 发布:网络大v颠倒是非 编辑:程序博客网 时间:2024/06/07 14:52

题目链接
这是2017CCPC网络赛的题目。比赛过程中,暴力打表,二分查找过的。

由于每个进制之下的回文数大概都不会超过14万,因此,开一个二维数组储存是可以的。接下来,我们就需要找出k进制下的回文数。(这里需要提一下一个算法,第N个回文数,如果和我一样之前并不知晓请自行百度)

//贴一下自己修改了的求k进制下第n个回文数的代码long long Find(int n,int k) {    long long Count = 0,num = k-1,w = 0,h = 1;    long long half,res;    while(true) {        if(w > 0 && w%2 == 0) {            num *= k;        }        w++;        if(Count + num > n)            break;        Count += num;    }    n -= Count;    for(int i = 0; i < (w-1) / 2; i++) {        h *= k;    }    half = h + n;    res = half;    if(w%2 != 0)        half /=k;    while(half != 0) {        res = res *k + half % k;        half /= k;    }    return res;}

接下来是AC的代码

#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll maxn = 1e9;ll a[37][150040];int Cnt[36];long long Find(int n,int k) {    long long Count = 0,num = k-1,w = 0,h = 1;    long long half,res;    while(true) {        if(w > 0 && w%2 == 0) {            num *= k;        }        w++;        if(Count + num > n)            break;        Count += num;    }    n -= Count;    for(int i = 0; i < (w-1) / 2; i++) {        h *= k;    }    half = h + n;    res = half;    if(w%2 != 0)        half /=k;    while(half != 0) {        res = res *k + half % k;        half /= k;    }    return res;}void init(){    for(int i=2;i<=36;i++)    {        int cnt = 0;        for(int j=0;;j++)        {            ll temp = Find(j,i);            if(temp>maxn)                break;            a[i][cnt++] = temp;        }        Cnt[i] = cnt;    }}int main(){    init();    int T;    scanf("%d",&T);    for(int tt=1;tt<=T;tt++)    {        ll L,R,l,r;        scanf("%lld %lld %lld %lld",&L,&R,&l,&r);        int temp;        ll ans =0;        for(ll i=l;i<=r;i++)        {            temp = upper_bound(a[i],a[i]+Cnt[i],R)-lower_bound(a[i],a[i]+Cnt[i],L);            ans += temp*i+(R-L+1-temp);        }        printf("Case #%d: %lld\n",tt,ans);    }}

以上只是比赛时的权宜之计,比赛后,自然要用数位dp来做。

开了三维的状态 第一个代表当前位置,第二个代表进制,第三个代表开始的位置

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll dp[40][40][40];int an[40],Num[40];ll dfs(int pos,int flag,int base,bool limit,int be){    if(pos<0)        return flag==0;    if(dp[pos][base][be]!=-1&&!limit&&!flag)        return dp[pos][base][be];    ll res=0;    int maxn=limit?Num[pos]:(base-1);    for(int i=0;i<=maxn;i++)    {        if(flag&&i==0)            res+=dfs(pos-1,flag,base,limit&&i==maxn,be);        else{            if(flag){               an[pos]=i;               res+=dfs(pos-1,0,base,limit&&i==maxn,pos);            }            else if(pos<(be+1)/2){                if(i==an[be-pos])                res+=dfs(pos-1,0,base,limit&&i==maxn,be);            }            else{                an[pos]=i;                res+=dfs(pos-1,0,base,limit&&i==maxn,be);            }        }    }    an[pos]=-1;    if(!limit&&!flag)        dp[pos][base][be]=res;    return res;}ll solve(int x,int base){    int len=0;    while(x)    {        Num[len++]=x%base;        x/=base;    }    return dfs(len-1,1,base,1,39);}int main(){    int T;    scanf("%d",&T);    memset(dp,-1,sizeof(dp));    for(int tt=1;tt<=T;tt++)    {        int l,r,L,R;        scanf("%d%d%d%d",&l,&r,&L,&R);        ll ans=0;        for(int i=L;i<=R;i++)        {            ll ret=solve(r,i)-solve(l-1,i);            ans+=ret*i+(r-l+1-ret);        }        printf("Case #%d: %lld\n",tt,ans);    }}
原创粉丝点击