hdu-6156

Palindrome Function

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others)
Total Submission(s): 809    Accepted Submission(s): 446


Problem Description
As we all know,a palindrome number is the number which reads the same backward as forward,such as 666 or 747.Some numbers are not the palindrome numbers in decimal form,but in other base,they may become the palindrome number.Like 288,it’s not a palindrome number under 10-base.But if we convert it to 17-base number,it’s GG,which becomes a palindrome number.So we define an interesting function f(n,k) as follow:
f(n,k)=k if n is a palindrome number under k-base.
Otherwise f(n,k)=1.
Now given you 4 integers L,R,l,r,you need to caluclate the mathematics expression Ri=Lrj=lf(i,j) .
When representing the k-base(k>10) number,we need to use A to represent 10,B to represent 11,C to repesent 12 and so on.The biggest number is Z(35),so we only discuss about the situation at most 36-base number.
 

Input
The first line consists of an integer T,which denotes the number of test cases.
In the following T lines,each line consists of 4 integers L,R,l,r.
( 1T105,1LR109,2lr36)
 

Output
For each test case, output the answer in the form of “Case #i: ans” in a seperate line.
 

Sample Input
  
  
3 1 1 2 36 1 982180 10 10 496690841 524639270 5 20
 

Sample Output
  
  
Case #1: 665 Case #2: 1000000 Case #3: 447525746

题意:给出L,R,l,r。求从进制l到进制r,数L与R之间回文数字个数。这道题一看就是数位dp,然后听说是模板题,其实,我码了一个数位dp,然后改了改,结果发现,其实不用数位dp也可以搞定,只需要一点预处理,就可以解决了。(其实是因为我不擅长数位dp)

题解:1、先预处理一个sum[i][j] 数组,为i进制下的j位没有限制且首位不为0的所有回文数的个数。然后做一下前缀和,就可以得到i进制下0到长度为j的回文数个数。

2、用0到R的回文数个数减去0到L-1的回文数个数就得到L到R中回文数个数。

3、对于当前询问的数字,先将其分解成当前进制下的数组,长度为len,然后现在目标即是算出在长度为len的受到限制且首位不为0的回文数个数,首先知道,在一个数字,比如654321中,前三位还没到达654前,后三位是没有限制的,于是回文数个数tmp = 654 - 99(这个99的意思是:因为你1到654中有1位数2位数3位数,所以有001这样的数,违反了我们前面定义的首位不为0,故将此部分减去),然后,此时tmp还有一点需要考虑,即当到达654时,是否可行(因为此时后三位已受到限制),这时就从中间枚举,即枚举这里的3,2,1,如果该位比其对应的那个对称数小,说明tmp-1(3小于4,不存在654456)如果该位比其对应得那个对称数大(假设原来要求的数为654500,5大于4,存在654456),则tmp不用减1,同样的,如果一直等下去,说明该树本身就是回文数,tmp一样不用减1。

4、此时我们找到sum[当前进制][长度为len-1],加上第3步求出来的tmp,就是0到该数的回文数个数。

5、按第2步做,做差相乘加和得到答案。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <functional>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
typedef long long ll;
const double eps = 1e-7;
const int maxn = 3e5+7;
const int INF = 1e9+7;

ll sum[40][40];
ll l,r,L,R,d,len;
ll b[40];
ll qpow(ll a,ll b){
    ll ans = 1;
    while(b){
        if(b&1){
            ans*=a;
        }
        a*=a;
        b>>=1;
    }
    return ans;
}


ll solve(ll a,ll bit){
    if(a==0) return 1;
    len = 0;
    while(a){
        b[len++] = a%bit;
        a/=bit;
    }
    d = len - (len-1)/2 - 1;
    int nlen = (len-1)/2 + 1;
    ll tmp = 0;
    for(int i = len-1;i >= d;i--){
        tmp*=bit;
        tmp+=b[i];
    }
    tmp-=qpow(bit,nlen-1)-1;
    int flag = 1;
    for(int i = nlen-1;i >= 0;i--){
        if(b[i]>b[len-i-1]){
            flag = 1;
            break;
        }
        else if(b[i]<b[len-i-1]){
            flag = 0;
            break;
        }
    }
    if(!flag) tmp-=1;
    //cout<<tmp<<" "<<sum[bit][len-1]<<endl;
    return tmp+sum[bit][len-1];
}

int main(){
    memset(sum,0,sizeof(sum));
    for(int i = 2;i <= 36;i++){
        sum[i][1] = sum[i][0] = 1;
    }
    for(int i = 2;i <= 36;i++){
        for(int j = 1;j < 40;j++){
            sum[i][j] += qpow(i,(j-1)/2)*(i-1);
            if(j!=1) sum[i][j] += sum[i][j-1];
        }
    }
    int t;
    scanf("%d",&t);
    int I = 1;
    while(t--){
        scanf("%lld %lld %lld %lld",&L,&R,&l,&r);
        ll ans = 0;
        ll all = R-L+1;
        for(int i = l;i <= r;i++){
            ll tmp = solve(R,i)-solve(L-1,i);
            ans+=tmp*i+all-tmp;
        }
        printf("Case #%d: ",I++);
        cout<<ans<<endl;
    }
    return 0;
}


### 关于HDU - 6609 的题目解析 由于当前未提供具体关于 HDU - 6609 题目的详细描述,以下是基于一般算法竞赛题型可能涉及的内容进行推测和解答。 #### 可能的题目背景 假设该题目属于动态规划类问题(类似于多重背包问题),其核心在于优化资源分配或路径选择。此类问题通常会给出一组物品及其属性(如重量、价值等)以及约束条件(如容量限制)。目标是最优地选取某些物品使得满足特定的目标函数[^2]。 #### 动态转移方程设计 如果此题确实是一个变种的背包问题,则可以采用如下状态定义方法: 设 `dp[i][j]` 表示前 i 种物品,在某种条件下达到 j 值时的最大收益或者最小代价。对于每一种新加入考虑范围内的物体 k ,更新规则可能是这样的形式: ```python for i in range(n): for s in range(V, w[k]-1, -1): dp[s] = max(dp[s], dp[s-w[k]] + v[k]) ``` 这里需要注意边界情况处理以及初始化设置合理值来保证计算准确性。 另外还有一种可能性就是它涉及到组合数学方面知识或者是图论最短路等相关知识点。如果是后者的话那么就需要构建相应的邻接表表示图形结构并通过Dijkstra/Bellman-Ford/Floyd-Warshall等经典算法求解两点间距离等问题了[^4]。 最后按照输出格式要求打印结果字符串"Case #X: Y"[^3]。 #### 示例代码片段 下面展示了一个简单的伪代码框架用于解决上述提到类型的DP问题: ```python def solve(): t=int(input()) res=[] cas=1 while(t>0): n,k=list(map(int,input().split())) # Initialize your data structures here ans=find_min_unhappiness() # Implement function find_min_unhappiness() res.append(f'Case #{cas}: {round(ans)}') cas+=1 t-=1 print("\n".join(res)) solve() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值