zoukankan      html  css  js  c++  java
  • 洛谷P4127

    Description

    给出两个数 (a)(b) ,求出 ([a,b]) 中各位数字之和能整除原数的数的个数


    Solution

    (f[i][j][k][q]) 表示 枚举到第 i 位,当前数字为 j ,各个数位上的数字和为 k,原数模 k 的余数为 q

    可以发现,从 i - 1 位推到第 i 位并不好推,所以可以转变一下

    用第 i 位推第 i + 1 位

    显然有

    [f[i+1][s][j+s][(k+s imes 10^i)\%x]=sum_{t=0}^9f[i][t][j][k] ]

    约束条件为 (iin [1,len])(jin [0,min{i imes 9,x}])(sin[0,9])(kin[0,x))

    其中 (i) 是枚举位数,(s) 是下一位上的数,(t) 是当前位上的数,(x) 是总数位和,(k) 是余数,(j) 是当前累计的数位和

    然后对于答案的统计:

    • 对于位数小于当前位的,(ans+=f_{i,10,x,0}) (−) (f_{i,0,x,0})
    • 对于位数相同的,计算小于最高位的 (ans+=f_{num_i,s,x,0})
    • 然后对于当前不同的一位进行讨论即可,计算出后面所需要的余数,然后加和

    (num_i)(i) 的最高位,(x) 是要求的位数和

    答案就是所有位数和的 (ans) 之和, 同时满足满足 ([l,r])


    Code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #define int long long
    
    using namespace std;	
    
    int A,B;
    int f[20][11][172][172];
    int highest[20],a[20][2];
    int Mod,Pow[20];
    
    inline int read(){
    	int s=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    	while(ch>='0' &&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    	return w*s;
    }
    
    inline int Min(int x,int y){return x<y?x:y;}
    inline void F(int x,int y){highest[y]=0;while(x){a[++highest[y]][y]=x%10;x/=10;}}
    
    inline void init(int x,int len){
    	memset(f,0,sizeof f);
    	for(register int i=0;i<=9;i++) f[1][i][i][i%x]++,f[1][10][i][i%x]++;
    	for(register int i=1;i<len;i++)
    		for(register int j=0;j<=Min(i*9,x);j++)
    			for(register int k=0;k<x;k++){
    				if(f[i][10][j][k])for(register int s=0;s<=9;s++){
    				    	f[i+1][s][j+s][(k+s*Pow[i])%x]+=f[i][10][j][k];
    				    	f[i+1][10][j+s][(k+s*Pow[i])%x]+=f[i][10][j][k];
    				    }
    			} 
    	Mod=x;
    }
    
    inline int solve(int s,int x){
    	int ans=0,num=a[highest[s]][s],now=num;
    	for(register int i=1;i<highest[s];i++) ans+=f[i][10][x][0]-f[i][0][x][0];//处理最高位之前
    	for(register int i=1;i<a[highest[s]][s];i++) ans+=f[highest[s]][i][x][0];//处理最高位 
    	if(x<now) return ans;
    	for(register int i=highest[s]-1;i;i--){
    		int tot=(x-num*Pow[i]%x)%Mod;
    		for(register int j=0;j<a[i][s];j++)ans+=f[i][j][x-now][tot];//操作最高位 
    		now+=a[i][s];num=(num*10+a[i][s])%Mod;
    		if(x<now) break;	
    	}
    	return ans;
    }
    
    signed main(){
    	int ans=0;A=read();B=read();F(A,0),F(B+1,1);Pow[0]=1;
    	for(register int i=1;i<=18;i++) Pow[i]=Pow[i-1]*10; 
    	for(register int i=1;i<=highest[1]*9;i++){init(i,highest[1]);ans+=solve(1,i)-solve(0,i);}
    	printf("%lld",ans);
    	return 0;
    }
    

  • 相关阅读:
    分享一下前一段时间的开发总结
    循环,梦
    从C#程序中调用非受管DLLs
    大学生零工资就业,谁之过?
    国外宽带用户的上网速度能达到多少呢?
    天沉沉,来个好天气吧
    虚伪,不只是形容一个人
    回头思考关于xml的使用
    从毕业生当中看人与人的差距
    C# 编码规则
  • 原文地址:https://www.cnblogs.com/KnightL/p/14070944.html
Copyright © 2011-2022 走看看