码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 11361 Investigating Div-Sum Property

时间:2020-04-01 01:00:53      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:ace   int   ati   --   print   代码   str   $1   cstring   

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

题目

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

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

有多少个数字。

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

题解

让人难过的数位dp

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

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

$32345()\quad32344()\cdots\quad32341()$

$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\n", ans);
	}
}

 

UVA 11361 Investigating Div-Sum Property

标签:ace   int   ati   --   print   代码   str   $1   cstring   

原文地址:https://www.cnblogs.com/sahdsg/p/12609617.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!