HDU 5936 && 2016CCPC杭州 D: Difference(折半枚举)



题意:

给你x和k,问你有多少个y满足题上的两个公式

y的位数不会超过10位,因为如果超过十位的话f(y, k)-y一定是个负数

比如假设y是11位,那么f(y, k)最大值是9^9*11它只有10位


这样可以将y强行填到10位,比如y=236,那么就让y=0000000236

这样就不用判断位数了

之后暴力出前5位的所有情况(0-99999)

举个例子:假设当时是25436,k为6,那么当前值就是2^6+5^6+4^6+3^6+6^6-25436*100000

将算出来的100000个值存到L[]数组里排个序,注意每个k都要这样算一次

然后再暴力算出后5位的所有情况(0-99999)

和上面一样的:假设当时是25436,k为6,那么当前值就是2^6+5^6+4^6+3^6+6^6-25436

将算出来的100000个值存到R[]数组里排个序,每个k都要这样算一次仍然


O(nklog(n)) (n=100000)的复杂度预处理结束后

每次询问x, k相当于找到有多少组R[]+L[]==x,因为R和L都是有序,这样就可以O(n)计算了

总复杂度O(nklog(n)+Tn)

注意当x=0时答案要-1,因为y!=0

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define LL long long
LL L[12][100005], R[12][100005], cnt[12], p[12][12];
int main(void)
{
	LL T, x, k, i, j, q, temp, sum, ans, cas = 1;
	for(i=0;i<=9;i++)
	{
		p[i][1] = i;
		for(j=2;j<=9;j++)
			p[i][j] = p[i][j-1]*i;
	}
	for(k=1;k<=9;k++)
	{
		for(i=0;i<=99999;i++)
		{
			sum = 0;
			temp = i;
			for(j=1;j<=5;j++)
			{
				sum += p[temp%10][k];
				temp /= 10;
			}
			L[k][++cnt[k]] = sum-i*100000;
			R[k][cnt[k]] = sum-i;
		}
		sort(L[k]+1, L[k]+cnt[k]+1);
		sort(R[k]+1, R[k]+cnt[k]+1);
	}
	scanf("%lld", &T);
	while(T--)
	{
		ans = 0;
		scanf("%lld%lld", &x, &k);
		q = cnt[k];
		for(i=1;i<=cnt[k];i++)
		{
			if(i!=1 && R[k][i]==R[k][i-1])
			{
				ans += sum;
				continue;
			}
			sum = 0;
			if(q<=0)  break;
			while(R[k][i]+L[k][q]>x && q>=1)  q--;
			while(R[k][i]+L[k][q]==x && q>=1)  q--, sum++;
			ans += sum;
		}
		if(x==0)
			ans--;
		printf("Case #%lld: %lld\n", cas++, ans);
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值