Beautiful numbers

本文介绍使用数位DP算法解决Beautifulnumbers问题的过程,通过优化状态表示减少内存消耗,最终实现有效求解区间内满足特定条件的数字数量。

Beautiful numbers

Codeforces55_D

HOJ1983

注意两边的提交格式和long long;int64不一样,细节


题意:【X,Y】区间内有多少个数,该数能够整除数位中的每一位

按照数位DP模板先走起

dp【pos】【num】【mod】表示:当前已经算到了第pos位,当前数为num,各个数位的乘积为mod

然后发现,空间没法开起来。

pos开20位,num要用1到1e18


各个数位的乘积mod,肯定会是1,2,3,4,5,6,7,8,9这9个数的最小公倍数的约数

2520共有多少个约数,暴力算一下,就几十个。

所以可以用数组先暴力算出来记住,用hash的方法省空间


这个时候num也自然就少了。因为数论,num%mod要等于0,等价于(num%2520)%mod==0

所以每次计算的时候,num不超过2520

最后数组开出来是dp【20】【2550】【50】,所以这样开数组可以开下来


然后就是套路代码,可以过CF55D的


#include<map>
#include<set>
#include<math.h>
#include<time.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cstdlib>
using namespace std;

#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define ll rt<<1
#define rr rt<<1|1
#define LL long long
#define ULL unsigned long long
#define maxn 1050
#define maxnum 1000050
#define eps 1e-6
#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)

__int64 dp[20][2525][55];
int digit[20];
int hash[2525];

int gcd(int a,int b){
	if (!b) return a;
	return gcd(b,a%b);
}

int lcm(int a,int b){
	return a/gcd(a,b)*b;
}

__int64 dfs(int pos,int num,int mod,bool flag){
	if (pos==0) return num%mod==0;
	if (flag&&dp[pos][num][hash[mod]]!=-1) return dp[pos][num][hash[mod]];
	int number=flag?9:digit[pos];
	__int64 ans=0;
	for(int i=0;i<=number;i++)
		ans+=dfs(pos-1,(num*10+i)%2520,i?lcm(mod,i):mod,flag||i<number);
	if (flag) dp[pos][num][hash[mod]]=ans;
	return ans;
}

__int64 calc(__int64 x){
	if (x<0) return 0;
	int len=0;
	while(x){
		digit[++len]=x%10;
		x/=10;
	}
	return dfs(len,0,1,0);
}

void init(){
	memset(dp,-1,sizeof(dp));
	int id=0;
	for(int i=1;i*i<=2520;i++)
		if (2520%i==0){
			hash[i]=id++;
			if (i*i!=2520) hash[2520/i]=id++;
		}
}

int main(){
	//input;
	init();
	int t;
	scanf("%d",&t);
	__int64 x,y;
	while(t--){
		scanf("%I64d%I64d",&x,&y);
		printf("%I64d\n",calc(y)-calc(x-1));
	}
	return 0;
}

感谢巨巨的题解:

http://blog.youkuaiyun.com/niuox/article/details/9864199

B. Shrinking Array time limit per test2 seconds memory limit per test256 megabytes Let's call an array b beautiful if it consists of at least two elements and there exists a position i such that |bi−bi+1|≤1 (where |x| is the absolute value of x ). You are given an array a , and as long as it consists of at least two elements, you can perform the following operation: Choose two adjacent positions i and i+1 in the array a . Choose an integer x such that min(ai,ai+1)≤x≤max(ai,ai+1) . Remove the numbers ai and ai+1 from the array, and insert the number x in their place. Obviously, the size of the array will decrease by 1 . Calculate the minimum number of operations required to make the array beautiful, or report that it is impossible. Input The first line contains one integer t (1≤t≤200 ) — the number of test cases. The first line of each test case contains one integer n (2≤n≤1000 ) — the size of the array a . The second line contains n integers a1,a2,…,an (1≤ai≤106 ) — the array a itself. Output For each test case, output one integer — the minimum number of operations needed to make the array a beautiful, or −1 if it is impossible to make it beautiful. Example InputCopy 4 4 1 3 3 7 2 6 9 4 3 1 3 7 4 1 3 5 2 OutputCopy 0 -1 1 1 Note In the first test case, the given array is already beautiful, as |a2−a3|=|3−3|=0 . In the second test case, it is impossible to make the array beautiful, as applying the operation would reduce its size to less than two. In the third test case, you can, for example, choose a1 and a2 and replace them with the number 2 . The resulting array [2,3,7] is beautiful. In the fourth test case, you can, for example, choose a2 and a3 and replace them with the number 3 . The resulting array [1,3,2] is beautiful. (C++)
最新发布
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值