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;
    }
    
  • 相关阅读:
    flask 实现增删改查
    juniper srx系列配置端口映射 转载
    form(form基础、标签渲染、错误显示 重置信息、form属性、局部钩子、全局钩子)
    postfix “ Sender address rejected: not logged in”
    Python 学习博客地址
    分页器(分页器基本操作、点击按钮分页、美化分页器)
    yuan先生博客地址
    Ajax(form表单文件上传、请求头之contentType、Ajax传递json数据、Ajax文件上传)
    Mysql容器启动失败-解决方案
    Ajax(简介、基础操作、计算器,登录验证)
  • 原文地址:https://www.cnblogs.com/tuchen/p/14021664.html
Copyright © 2011-2022 走看看