zoukankan      html  css  js  c++  java
  • LZUoj 回文整数求和 (数位dp)

    题目链接:http://oj.lovelyanqi.com/problem/L04 K

    想知道 ([0, x]) 之内有多少个回文数,

    假设 (x)(c) 位,我们可以先预处理出前 (c - 1) 位内 ((99....99)) 的答案
    然后再加上 (10^{c-1})(x) 内的答案即可

    考虑如何统计,需要对 (x) 的数位分奇偶性讨论

    如果数位是奇数
    例如 (12345) ,则前半部分为 ([10,12])
    以第三位的数为中间点,如果前半部分 (left_x)([10,11]), 则中间数位可以为 ([0,9]) 的任意数,
    如果 (left_x)(12), 则中间数位只能为 ([0,3]) 之间的数,否则就会大于 (x)

    偶数的情况类似,不过没有了中间点

    重头戏来了

    如果为奇数

    (lx)为前半部分的数, (M) 为中间位置的数, (rx)(lx) 倒置过来的数 ((12345 -> 54321)), 记为 (rx = reverse(lx))

    先考虑 (lx < left_x) 的情况:
    当前半部分小于 (left_x) 时,形如 (lx M rx) 的都为合法答案,其中 (lx < left_x, M 属于 [0,9], rx = reverse(lx))

    分别考虑 (lx , M ,rx) 的贡献,(lx) 贡献了 (sumlx * 10^{c / 2}),
    (rsum) 表示所有合法 (rx) 的和,则 (sumx) 贡献了 $ 10 $ 次 (M = [0,9])都贡献一次,即为 $ M * rsum $.

    再考虑 (lx = left_x) 的情况:
    (M < M_x) 时,(rsum_x) 贡献了 (M) 次,
    (M = M_x) 时,需要比较 (reverse(rx))(lx) 的大小关系,
    如果 (reverse(rx) > lx), 则 (left_x M_x reverse(left_x)) 为合法回文数,需要加上其自身的贡献

    否则不合法,不需要算贡献

    偶数的情况类似,不过要比奇数的情况简单很多,可以自己尝试推一下

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 1000010;
    
    int T, a, b;
    ll sum[maxn], rsum[10010], po[15];
    ll S[15] = {1, 45, 540, 50040, 545040, 50045040, 545045040, 50045045040, 545045045040, 50045045045040};
    
    int f[15];
    
    int rev(int x){
    	int res = 0;
    	int cnt = 0;
    	int tmp = x;
    	while(tmp){
    		f[++cnt] = tmp % 10;
    		tmp /= 10;
    	}
    	for(int i = 1 ; i <= cnt ; ++i){
    		res += f[i] * po[cnt - i];
    	}
    	
    	return res;
    }
    
    ll calc(int x){
    	ll res = 0;
    	int cnt = 0;
    	int tmp = x;
    	while(tmp){
    		++cnt;
    		tmp /= 10;
    	}
    	
    	res = 1ll * (po[cnt - 1] + x - 1) * (x - po[cnt - 1]) / 2; 
    	
    	return res;
    }
    
    void init(){
    	for(int i = 1 ; i <= 9999 ; ++i){
    		rsum[i] = rsum[i - 1] + rev(i);
    	}
    	for(int i = 1 ; i <= 99999 ; ++i){
    		sum[i] = calc(i);
    	}
    }
    
    ll solve(int x){
    	if(x == -1) return 0;
    	ll res = 0;
    	
    	int cnt = 0;
    	int tmp = x;
    	while(tmp){
    		++cnt;
    		tmp /= 10;
    	}
    	
    	int lx = x / po[cnt / 2], rx = x % po[cnt / 2], rlx = rev(lx) % po[cnt / 2] ;
    	res = S[cnt - 1];
    	res += 1ll * sum[lx] * po[cnt / 2];
    	if(cnt % 2 == 0){
    		res += rsum[lx - 1] - rsum[po[cnt / 2 - 1] - 1];
    		
    		if(rlx <= rx){
    			res += 1ll * lx * po[cnt / 2] + rlx;
    		}
    	} else{
    		int plx = lx / 10, rem = lx % 10;
    		
    		res += 1ll * 10 * ( rsum[plx - 1] - rsum[po[cnt / 2 - 1] - 1]);
    		
    		if(rev(plx) <= rx){
    			res += 1ll * rem * ( rsum[plx] - rsum[plx - 1]);
    			res += 1ll * lx * po[cnt / 2];
    			res += rsum[plx] - rsum[plx - 1]; // 给新加的加上 
    		} else{
    			res += 1ll * rem * ( rsum[plx] - rsum[plx - 1]);
    		}
    	}
    	
    	return res;
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	po[0] = 1;
    	for(int i = 1 ; i <= 10 ; ++i) po[i] = 1ll * po[i - 1] * 10;
    	init();
    	
    	T = read();
    	while(T--){
    		a = read(), b = read();
    		if(a == 1000000000) --a;
    		if(b == 1000000000) --b;
    		ll ansa = 0, ansb = 0 ;
    		if(a - 1 < 10){
    			for(int i = 1 ; i <= a - 1 ; ++i) ansa += i;
    		} else{
    			ansa = solve(a - 1);
    		}
    		if(b < 10){
    			for(int i = 1 ; i <= b ; ++i) ansb += i;
    		} else{
    			ansb = solve(b);
    		}
    		printf("%lld
    ", ansb - ansa);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Centos 7 zabbix 实战应用
    Centos7 Zabbix添加主机、图形、触发器
    Centos7 Zabbix监控部署
    Centos7 Ntp 时间服务器
    Linux 150命令之查看文件及内容处理命令 cat tac less head tail cut
    Kickstart 安装centos7
    Centos7与Centos6的区别
    Linux 150命令之 文件和目录操作命令 chattr lsattr find
    Linux 发展史与vm安装linux centos 6.9
    Linux介绍
  • 原文地址:https://www.cnblogs.com/tuchen/p/14021664.html
Copyright © 2011-2022 走看看