牛客网Wannafly挑战赛29 B - 白井黑子 乱搞

38 篇文章 0 订阅

Description


kuroko 作为常盘台唯一的空间系能力者,在每年例行的能力测试中可绝对不能让 misaka 失望哦,但是由于她的等级只是 level 4「大能力者」,在能力测试中会遇到不少困难。kuroko 是一个凡事都会尽力的好女孩,所以请你帮她算出她最多能完成多少测试吧

对于空间系能力者测试的内容是检验对物体进行空间移动的能力,测验时一共有 n 个物品放在一条直线上,每个物品都有一个坐标 ai ,kuroko 可以选择两个物品并使用能力交换它们的位置,但是如果两个物品的坐标不满足 kuroko 的计算公式的话,她就没有办法使用能力。

具体来说,对于坐标 ai ,其在 kuroko 的计算公式中是用参数 f(ai) 表示的。f(ai) 是 ai 各数位相乘的结果,由于 level 4「大能力者」在学园都市中也是很强大的存在,所以满足公式的条件不会太苛刻,对于两个物品 ai, aj ,如果 f(ai) x f(aj) 不能被某个自然数的 k 次幂表示 的话,那么 kuroko 就能对这两个物品使用能力。

现在 kuroko 想知道,有多少对物品她可以对其施展能力,知道了这个后她就知道自己能完成多少测验了。

这里认为任何自然数的 0 次幂都是 1。

2 ≤ n ≤ 105, 0 ≤ ai, k ≤ 1018

Solution


我们把f分解一下,质数只有2、3、5、7四种。两数相乘是某个自然数的k次幂说明它们指数上和模k为0。由于260小于1018,我们开604的桶直接统计就没了
注意k=0和k=1的情况

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int N=200005;

LL cnt[63][63][63][63],p[N][4];

LL a[N],k;

int n,tot;

void solve1() {
	LL ans=1LL*n*(n-1)/2;
	rep(i,1,n) {
		LL v,x=1; scanf("%lld",&v);
		for (;v;v/=10) x=x*(v%10);
		if (!x) continue;
		a[++tot]=x;
		for (;x%2==0;x/=2) p[tot][0]++; p[tot][0]%=k;
		for (;x%3==0;x/=3) p[tot][1]++; p[tot][1]%=k;
		for (;x%5==0;x/=5) p[tot][2]++; p[tot][2]%=k;
		for (;x%7==0;x/=7) p[tot][3]++; p[tot][3]%=k;
	}
	rep(i,tot+1,n) ans=(ans-(n-i+tot));
	n=tot;
	rep(i,1,n) {
		if ((k-p[i][0]%k)%k<=60&&(k-p[i][1]%k)%k<=60&&(k-p[i][2]%k)%k<=60&&(k-p[i][3]%k)%k<=60) {
			ans-=cnt[(k-p[i][0]%k)%k][(k-p[i][1]%k)%k][(k-p[i][2]%k)%k][(k-p[i][3]%k)%k];
		}
		cnt[p[i][0]][p[i][1]][p[i][2]][p[i][3]]++;
	}
	printf("%lld\n", ans);
}

void solve3() {
	LL ans=(n-1)*n/2,wjp=0;
	rep(i,1,n) {
		LL v,x=1; scanf("%lld",&v);
		for (;v;v/=10) x=x*(v%10);
		a[i]=x;
		if (x==1) wjp++;
		if (!x) continue;
		for (;x%2==0;x/=2) p[i][0]++;
		for (;x%3==0;x/=3) p[i][1]++;
		for (;x%5==0;x/=5) p[i][2]++;
		for (;x%7==0;x/=7) p[i][3]++;
	}
	printf("%lld\n", ans-(wjp-1)*wjp/2);
}

int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	scanf("%d%lld",&n,&k);
	if (k==0) solve3();
	else if (k==1) puts("0");
	else solve1();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值