2021牛客寒假算法基础集训营1

比赛链接


I.限制不互素对的排列

题目描述

输入一个数 \(n\) ,请构造一个长度为 \(n\) 的排列,使得其中正好有 \(k\) 对相邻的数gcd(最大公约数)大于 1 。 排列是指 1 到 \(n\) 一共 \(n\) 个数,每个数都出现过且仅出现过 1 次。例如, \(\{1,3,2,5,4\}\) 是一个排列,而 \(\{1,3,4,5,3\}\)\(\{1,2,4\}\) 则不是排列

输入描述:

两个整数 \(n\)\(k\), 用空格隔开。
\(2 \leq n \leq 100000,0 \leq k \leq n / 2\)

输出描述:

如果不存在可行的构造方案, 输出 \(-1\)
否则输出一行 \(n\) 个数, 用空格隔开。如果有多组可行的构造方案, 输出任意一组即可。

解题思路

构造
所有连续的自然数互质,所有连续的奇数互质

由于 \(k\leq n/2\),即 \(k\) 不算很大,可以分两种情况”

  • \(k<n/2\),可以先输出 \(k+1\) 个偶数,再输出最后输出的偶数后面的所有数,然后再输出前面的奇数

  • \(k=n/2\),这时即使算上所有的偶数还少了一个,可以将 \(6\)\(3\) 放在后面,然后再输出那些剩余的奇数

  • 时间复杂度:\(O(n)\)

代码

// Problem: 限制不互素对的排列
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30716/I
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=100005;
bool v[N];
int n,k;
int main()
{
    cin>>n>>k;
    if(n<6&&k==n/2)
    {
        puts("-1");
        return 0;
    }
    if(k<n/2)
    {
        int i=2;
        for(int j=0;j<=k;j++,i+=2)cout<<i<<' ';
        i-=2;
        for(int j=i+1;j<=n;j++)cout<<j<<' ';
        for(int j=1;j<=i;j+=2)cout<<j<<' ';
    }
    else
    {
        int i=8;
        for(int j=1;i<=n&&j<=k-2;j++,i+=2)cout<<i<<' ';
        cout<<"2 4 6 3 1 ";
        for(int i=5;i<=n;i+=2)cout<<i<<' ';
    }
    return 0;
}

J.一群小青蛙呱蹦呱蹦呱

题目描述

\(n\)个格子,每个格子里有一个数,\(1,2,3,4...n\)

牛牛放出无穷只青蛙。
第一只青蛙的路线是:1->2->4->8->16->....
第二只青蛙的路线是:1->3->9->27->81->....
第三只青蛙的路线是:1->5->25->125....
第四只青蛙的路线是:1->7->49........
。。。。。。
用数学语言描述,第 \(i\) 只青蛙的路线是首项为\(1\),公比为\(p(i)\) 的等比数列,其中\(p(i)\) 代表第\(i\) 个素数。
当青蛙跳到一个格子上,如果这个格子上面有一个数,青蛙就会把这个数吃掉。
牛牛想知道,所有没有被吃掉的数的lcm(最小公倍数 ,Least common multiple)是多少?
由于这个lcm可能非常大,请输出它对\(10^9+7\) 取模的值。

输入描述:

一个正整数\(n\)
\(1\leq n \leq 1.6 \times 10^8\)

输出描述:

如果所有数都被吃掉了,请输出一个字符串"empty"
否则输出所有没有被吃掉的数的lcm,对\(10^9+7\) 取模

示例1

输入

7

输出

6

说明

数字 1 可以被所有青蛙吃掉;
数字 2 可以被第 1 只青蛙吃掉;
数字 3 可以被第 2 只青蛙吃掉;
数字 4 可以被第 1 只青蛙吃掉;
数字 5 可以被第 3 只青蛙吃掉;
数字 6 无法被吃掉;
数字 7 可以被第 4 只青蛙吃掉。
所以剩下的数字只有一个 6 ,所有数的 lcm 为 6

示例2

输入

123456789

输出

539747460

解题思路

思维
多个数的最小公倍数为所有数分解质因数,对应幂次最大的质因数幂次方的乘积

考虑每个质因数的贡献,对于一个质因数 \(p\) 来说,\(p=2\) 时,显然要找到 \(3\times 2^k\leq n\) 最大的 \(k\)\(p>2\) 时,要找到 \(2\times p^k\leq n\) 最大的 \(k\)

  • 时间复杂度:\(O(n)\)

代码

// Problem: 一群小青蛙呱蹦呱蹦呱
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30716/J
// Memory Limit: 2097152 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=8e7+5,mod=1e9+7;
int prime[N],m,n;
bool v[N];
void primes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!v[i])prime[++m]=i;
		for(int j=1;prime[j]<=n/i;j++)
		{
			v[prime[j]*i]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int main()
{
	primes(N-1);
    cin>>n;
    if(n<6)
    {
        puts("empty");
        return 0;
    }
    int res=1;
    for(int i=2;i<=m;i++)
    {
    	if(2*prime[i]>n)break;
        int t=1;
        while(1ll*t*prime[i]<=n/2)t*=prime[i];
        res=1ll*res*t%mod;
    }
    int t=1;
    while(1ll*t*2<=n/3)t*=2;
    res=1ll*res*t%mod;
    cout<<res;
    return 0;
}
posted @ 2022-03-21 22:28  zyy2001  阅读(30)  评论(0编辑  收藏  举报