2020牛客暑期多校训练营(第四场)

B Basic Gcd Problem

题意:

给出 n , c n,c n,c 让你求出那个函数的值。

举个例子:

n = 6 , c = 3 n=6,c=3 n=6,c=3

f 3 ( 5 ) = m a x { 3 ∗ f 3 ( c d ( 1 , 6 ) ) , 3 ∗ f 3 ( g c d ( 2 , 6 ) ) , 3 ∗ f 3 ( c d ( 3 , 6 ) ) , 3 ∗ f 3 ( c d ( 4 , 6 ) ) , 3 ∗ f 3 ( c d ( 5 , 6 ) ) } f_3(5)=max\{3*f_3(cd(1,6)),3*f_3(gcd(2,6)),3*f_3(cd(3,6)),3*f_3(cd(4,6)),3*f_3(cd(5,6))\} f3(5)=max{3f3(cd(1,6)),3f3(gcd(2,6)),3f3(cd(3,6)),3f3(cd(4,6)),3f3(cd(5,6))}

= m a x { 3 ∗ f 3 ( 1 ) , 3 ∗ f 3 ( 2 ) , 3 ∗ f 3 ( 3 ) , 3 ∗ f 3 ( 2 ) , 3 ∗ f 3 ( 1 ) } =max\{3*f_3(1),3*f_3(2),3*f_3(3),3*f_3(2),3*f_3(1)\} =max{3f3(1),3f3(2),3f3(3),3f3(2),3f3(1)}

继续递推下去:

f 3 ( 2 ) = m a x { 3 ∗ f 3 ( g c d ( 1 , 2 ) } f_3(2)=max\{3*f_3(gcd(1,2)\} f3(2)=max{3f3(gcd(1,2)}
f 3 ( 3 ) = m a x { 3 ∗ f 3 ( g c d ( 1 , 3 ) , 3 ∗ f 3 ( g c d ( 2 , 3 ) } f_3(3)=max\{3*f_3(gcd(1,3),3*f_3(gcd(2,3)\} f3(3)=max{3f3(gcd(1,3),3f3(gcd(2,3)}

即:

= m a x { 3 , 3 ∗ 3 , 3 ∗ 3 , 3 ∗ 3 , 3 ∗ 3 } =max\{3,3*3,3*3,3*3,3*3\} =max{3,33,33,33,33}

就是看 c c c 的贡献,也就是 n n n 有多少个质因子可以被分解多少次。

AC代码:
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mxn = 1000010, mo = 1000000007;
int p[mxn], lo[mxn], t;
bool vis[mxn];

ll pw(ll a, ll b)
{
	ll r = 1;
	while (b)
	{
		if (b & 1)
			r = r * a % mo;
		a = a * a % mo;
		b >>= 1;
	}
	return r;
}
void shai(int n)
{
	t = 0;
	vis[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if (!vis[i])
		{
			p[++t] = i;
			lo[i] = i;
		}
		for (int j = 1; j <= t && p[j] * i <= n; j++)
		{
			vis[p[j] * i] = 1;
			lo[p[j] * i] = p[j];
			if (i % p[j] == 0)
				break;
		}
	}
}
int main()
{
	int T, n, c;
	shai(1000000);
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &n, &c);
		int cnt = 0;
		while (n > 1)
		{
			int x = lo[n];
			n /= x;
			cnt++;
		}
		int ans = pw(c, cnt);
		printf("%d\n", ans);
	}
	return 0;
}

F Finding the Order

题意:

给出两条平行线 l 1 l_1 l1 l 2 l_2 l2 l 1 l_1 l1 上有 A 、 B A、B AB 两点, A A A B B B 的左边, l 2 l_2 l2 上有 C 、 D C、D CD 两点但 C 、 D C、D CD 两点的相对位置不知道,给出 A C , A D , B C , B D AC, AD ,BC ,BD AC,AD,BC,BD的长度,判断 C C C D D D 的左还是右边。

分情况讨论就行了。

AC代码:
int main()
{
    int t;
    sd(t);
    while (t--)
    {
        int ac, ad, bc, bd;
        sdd(ac, ad);
        sdd(bc, bd);
        if (bc == bd)
        {
            if (ad > ac)
                puts("AB//CD");
            else
                puts("AB//DC");
        }
        else if (bd > bc)
        {
            if (ad > ac)
                puts("AB//CD");
            else
                puts("AB//DC");
        }
        else
        {
            if (ac > ad)
                puts("AB//DC");
            else
                puts("AB//CD");
        }
    }
    return 0;
}

H Harder Gcd Problem

题意:

N N N 个苹果,编号为 1   N 1~N 1 N。现要将苹果组成若干对,每对苹果最小公约数不为 1 1 1 。求最多能分成多少对,输出各对的组成。

1 − n 1-n 1n 中的数先预处理里出来他们的最小质因子,把 1 − n 1-n 1n 所有数的最小质因子存起来,从大到小遍历,是当前质因子倍数个数偶数的直接两两分组,奇数的最小的那个可以判断他的一倍和二倍是否可以匹配,最后看看 2 2 2 的倍数还有多少偶数个没匹配的。

AC代码:
const int N = 5e5 + 50;
int zyz[N], prim[N], cnt = 0, vis[N];
vector<int> v[N];

void init(int n)
{
	rep(i, 2, n)
	{
		if (!zyz[i])
			prim[++cnt] = i;
		for (int j = i; j <= n; j += i)
			if (!zyz[j])
				zyz[j] = i;
	}
}

void get_pos(int n)
{
	rep(i, 1, n)
	{
		if (zyz[i])
		{
			int pos = lower_bound(prim + 1, prim + cnt + 1, zyz[i]) - prim; //每个数最小质因子的的位置
			v[pos].pb(i);
		}
	}
}

int main()
{
	int t;
	sd(t);
	init(200010);
	while (t--)
	{
		int n;
		sd(n);
		rep(i, 1, n)
		{
			v[i].clear();
			vis[i] = 0;
		}
		get_pos(n);
		int pos = upper_bound(prim + 1, prim + cnt + 1, n) - prim;
		pos--;
		vector<PII> ans;
		per(i, pos, 1)
		{
			if (i == 1)
			{
				vector<int> res;
				res.clear();
				for (auto i : v[i])
					if (!vis[i])
						res.pb(i);
				for (int j = 0; j < res.size(); j += 2)
					if (j + 1 < res.size())
						ans.pb(make_pair(res[j], res[j + 1]));
			}
			else
			{
				int len = v[i].size();
				if (len % 2 == 0)
				{
					for (int j = 0; j < len; j += 2)
					{
						if (j + 1 < len)
							ans.pb(make_pair(v[i][j], v[i][j + 1]));
						vis[v[i][j]] = 1;
						vis[v[i][j + 1]] = 1;
					}
				}
				else
				{
					for (int j = 1; j < len; j += 2)
					{
						if (j + 1 < len)
							ans.pb(make_pair(v[i][j], v[i][j + 1]));
						vis[v[i][j]] = 1;
						vis[v[i][j + 1]] = 1;
					}
					if (2 * v[i][0] <= n)
					{
						ans.pb(make_pair(v[i][0], 2 * v[i][0]));
						vis[v[i][0]] = 1;
						vis[2 * v[i][0]] = 1;
					}
				}
			} 
		}
		pd(ans.size());
		for (auto i : ans)
			pdd(i.fi, i.se);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值