【补题】Codeforces 1033 : Lyft Level 5 Challenge 2018 - Elimination Round (ABCD)

版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/82969689

前言

又是发布失败,全部清空,重写一遍。
再这样一次,我就不用csdn了。

When everything’s lost they pick up their hearts and avenge defeat.
League of Legends - Legends Never Die

总结

  1. java.math.BigInteger.isProbablePrime(int)可以判断给定的概率下是否是素数,参数越大耗时越多,也越准确。
  2. 与序列有关的题目要分清楚变量表示的是值还是下标。
  3. 分解质因数,求gcd时要考虑是否相等。

A. King Escape 水

国王和目标点必须在以皇后为原点的坐标系中的同一象限。

(bx-ax)*(cx-ax)>0 && (by-ay)*(cy-ay)>0

B. Square Difference 数学

a 2 b 2 a^2-b^2 是否为素数。(1<=b<a<=1e11)

a b = = 1 a + b a-b==1且a+b 为素数时,原数为素数, O ( n ) O(√n) 判断即可。
附一个java的神仙写法:

// LittleFall : Hello!
import java.util.*;
import java.math.*;

public class Main
{
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for(int xt = 0; xt < t; ++xt)
        {
            BigInteger a = sc.nextBigInteger(), b = sc.nextBigInteger();
            a = a.multiply(a).subtract(b.multiply(b));
            System.out.println(a.isProbablePrime(20)?"YES":"NO");
        }
    }
}

C. Permutation Game 博弈

给定排列P。Alice和Bob玩游戏,初始时弹珠在位置x上,如果存在一个位置y使得 P [ y ] &gt; p [ x ] y x % P [ x ] = = 0 P[y]&gt;p[x]且|y-x| \% P[x]==0 ,那么玩家可以把弹珠移到位置y上。轮流操作,Alice先手,两人绝顶聪明,最先不能操作的人输,问每个初始位置时谁赢?

如果一个状态能转移到必败态,那么它是必胜态,否则是必败态。

n为必败态,从n-1到1依次检查即可,由调和级数求和公式,复杂度 O ( n l o g n ) O(nlogn) .
序列题一定要分清楚变量表示值还是下标。

int save[M]; //序列
int id[M]; //每个数在序列中的位置
int tag[M]; //tag[i]表示序列中第i个位置必胜还是必败1/2
int main(void)
{
	int n = read();
	for(int i=1;i<=n;++i)
	{
		save[i]=read();
		id[save[i]] = i;
	}
	for(int num=n;num;--num)
	{
		int nxt = id[num]%num; //位置
		for(;nxt<=n;nxt+=num) 
			if(save[nxt]>num && tag[nxt]==2)
				tag[id[num]]=1;
		if(tag[id[num]]!=1)
			tag[id[num]]=2;
	}
	for(int i=1;i<=n;i++)
		putchar(tag[i]==1?'A':'B');

    return 0;
}

D. Divisors 数学

给出n(500)个因数只有3到5个的数(1e18),求它们积的因数个数。

唯一分解定理:
在这里插入图片描述

如果知道了最后数字的各个质因数个数,那么就可以快速地求出因数个数。
由唯一分解定理

  • 因数个数为3:2*2
  • 因数个数为4:2*2*2,2*3
  • 因数个数为5:2*2*2*2

首先可以用二分或者其他方法判断数字是否是质数的4,3,2次幂(注意先判4次再判2次),将质数记录下来。
剩下的数全部是两个质数的乘积,用已知的质数去试除这些数,将新得到的质因子也记录下来。
对所有不相等的两质数乘积两两求gcd,又可以得到若干质数。

对所有的数字拿这些质数去分解,记录这些质数出现了多少次。
还剩下的数字就是由没有出现过的质数组合而成。

使用唯一分解定理组合即得到答案。

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline ll read();
const int M = 500016, MOD = 998244353;

ll save[M];
int tag[M];
map<ll,int> mp;
ll sqr(ll num, ll p)
{
	ll l=1,r;
	if(p==2) r=2*MOD;
	else if(p==3) r=1500000;
	else if(p==4) r=40000;

	while(l<=r)
	{
		ll mid = (l+r)>>1;
		ll tmp=1;
		for(int i=0;i<p;i++)
			tmp *= mid;
		if(tmp==num) return mid;
		else if(tmp<num) l=mid+1;
		else if(tmp>num) r=mid-1;
	}
	return -1;
}
int main(void)
{
	int n = read();
	for(int i=0;i<n;++i) save[i] = read();

	//第一次扫描,开4/3/2次根号,如果成功则标记1
	for(int i=0;i<n;++i)
	{
		for(int p=4;p>=2;--p)
		{
			ll tmp = sqr(save[i], p);
			if(tmp!=-1)
			{
				printf("? p=%d\n",p );
				mp[tmp] = 0;
				tag[i] = 1;
				break;
			}
		}
	}
	//第二次扫描,使用已知素数进行检测
	for(int i=0;i<n;i++) if(tag[i]!=1)
		for(auto x : mp)
			if(save[i] % x.first==0)
				mp[save[i]/x.first]=0, tag[i]=2;
	//第三次扫描,两两之间尝试求gcd
	for(int i=0;i<n;++i) if(tag[i]!=1)
		for(int j=i+1;j<n;++j) if(tag[j]!=1 && save[i]!=save[j])
		{
			ll x = __gcd(save[i],save[j]);
			if(x!=1)
			{
				mp[x] = 0;
				mp[save[i]/x]=0;
				mp[save[j]/x]=0;
				tag[i]=2;
				tag[j]=2;
			}
		}
	//第四次扫描,找到剩下的独立素数个数
	map<ll,int> subs;
	for(int i=0;i<n;++i)
		if(tag[i]==0)
			subs[save[i]]++;
	//mp.erase(1);
	//第五次扫描,得出各素因数个数
	for(int i=0;i<n;++i)
		for(auto &x : mp)
			while(save[i] % x.first==0)
			{
				save[i]/=x.first;
				x.second++;
			}
	ll ans = 1;
	for(auto x:mp)
	{
		//printf("%I64d %d\n",x.first,x.second );
		ans = ans * (x.second+1) % MOD;
	}
	for(auto x:subs)
	{
		//printf("%I64d %d\n",x.first,x.second );
		ans = ans * (x.second+1) % MOD;
		ans = ans * (x.second+1) % MOD;
	}
	cout << ans << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/82969689
今日推荐