zoukankan      html  css  js  c++  java
  • UVA 11361 Investigating Div-Sum Property

    https://vjudge.net/problem/UVA-11361

    题目

    求[a,b]范围内,满足

    1. 它是k的倍数
    2. 它每一位和是k的倍数

    有多少个数字。

    $1leqslant aleqslant b<2^{31}$,$0<K<10^4$

    题解

    让人难过的数位dp

    设一个数字形状是 /?????(*)/ ,没有前导零,括号内的部分是自由的数,其余部分是固定的数

    比如32345就可以分为一系列这样的数

    $32345()quad32344()cdotsquad32341()$

    $32340()quad3233(*)quad3232(*)quad3231(*)$

    $3230(*)quad322(**)quad321(**)$

    $320(**)quad31(***)$

    $30(***)quad 2(****)quad1(****)$

    然后还有一些位数不足5位的数字

    $?(*)quad ?(**)quad ?(***)$

    这样就可以枚举出所有小于等于x的数字,循环次数为“各位的和”,时间复杂度$mathcal{O}(log n)$

    设f[x][m1][m2]为有x个自由的数,每一位和取模是m1,将自由的数设为0,然后这个数取模是m2,这种数字有多少个符合要求的

    那么就可以用加法原理解了

    还有个问题,根据贪心,K大于82时答案肯定为0,所以可以存下f数组

    这个写法比较麻烦,特别时枚举部分,而且还慢(因为把不需要使用的f也算出来了),只是为了弄清楚枚举“模板”怎么写

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<set>
    #define REP(i,a,b) for(int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(int i=(a); i<=(b); i++)
    #define PERE(i,a,b) for(int i=(a); i>=(b); i--)
    using namespace std;
    typedef long long ll;
    int f[10][107][107];
    int ten[10]={1,10,100,1000,10000,int(1e5),int(1e6),int(1e7),int(1e8),int(1e9)};
    int k;
    inline void calcf() {
    	memset(f,0,sizeof f);
    	f[0][0][0]=1;
    	REPE(i,1,9) REP(a,0,k) REP(b,0,k) REPE(z,0,9) { //?*10^i
    		int na=(a+z)%k, nb=(b+ten[i-1]%k*z)%k;
    		f[i][a][b]+=f[i-1][na][nb];
    	}
    }
    int F(int x) {
    	int w=0,t=x,ans=0,m1,m2,tt;
    	while(t>0) {//枚举位数相同的数
    	//把后缀有0的数放在前面计算的原因是避免开头就是后缀有0的数
    		m1=0,m2=t*ten[w];
    		tt=t;
    		while(tt>0) {
    			m1+=tt%10;tt/=10;
    		}
    		ans+=f[w][m1%k][m2%k];
    		while(t%10==0) { t/=10, w++; }
    		t--;
    		while(t%10>0) {
    			m1=0,m2=ten[w]*t;
    			tt=t;
    			while(tt>0) {m1+=tt%10; tt/=10;}
    			ans+=f[w][m1%k][m2%k];
    			t--;
    		}
    	}
    	REP(i,0,w) REPE(z,1,9) { //枚举位数较小的数
    		ans+=f[i][z%k][ten[i]*z%k];
    	}
    	return ans;
    }
    int main() {
    	int T; scanf("%d", &T);
    	while(0<T--) {
    		int a,b;
    		scanf("%d%d%d", &a, &b, &k);
    		if(k>82) {puts("0"); continue;}
    		calcf();
    		int ans=F(b)-F(a-1);
    		printf("%d
    ", ans);
    	}
    }
    
  • 相关阅读:
    多输出感知机及其梯度
    《机器学习实战》-线性回归
    《机器学习实战》-逻辑(Logistic)回归
    SQL Server 空间监测
    SQL Server 从数据库快照还原数据库
    SQL Server 创建数据库快照
    SQL Server 数据库的自动选项
    SQL Server 数据库游标选项
    SQL Server 数据库状态选项
    MYSQL 二进制还原
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12609617.html
Copyright © 2011-2022 走看看