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

比赛链接

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

I.牛牛的“质因数”

题目描述

算数基本定理,又称唯一分解定理,算术基本定理可表述为:任何一个大于1的自然数 \(\mathrm{N}\),如果 \(\mathrm{N}\) 不为质数,那么 \(\mathrm{N}\) 可 以唯一分解成有限个质数的乘积。即 \(N=p_{1}^{e 1} \cdot p_{2}^{e 2} \ldots p_{m}^{e m}\left(p_{1}<p_{2}<\ldots p_{m}\right)\)
朴素的质因子分解算法就是利用了算数基本定理,依次枚举p判断 \(N\) 是否包含素因子 \(p_{\text {。 }}\)
牛牛最近对于质因数分解产生了浓厚的兴趣。
牛牛定义了一个函数 \(F(x)\) ,它表示将x做质因数分解后得到的数字从小到大升序排列,然后将其 “拼接"成一个大整数。
例如 \(1500=2^{*} 2^{\star} 3^{\star} 5^{\star} 5^{\star} 5, F(1500)=223555\)
牛牛现在想要知道 \(\sum_{i=2}^{n} F(i)\) 的值。
由于这个结果非常大,所以你只用告诉牛牛最终答案对 \(10^{9}+7\) 取余数的结果即可。

输入描述:

仅一行一个正整数 \(n\left(2 \leq n \leq 4 \times 10^{6}\right)\)

输出描述:

仅一行, 表示答案对 \(10^{9}+7\) 取余数的结果。

示例1

输入

3

输出

5

示例2

输入

10

输出

342

说明

F(2)=2
F(3)=3
F(4)=22
F(5)=5
F(6)=23
F(7)=7
F(8)=222
F(9)=33
F(10)=25
2+3+22+5+23+7+222+33+25=342

解题思路

筛质数

对于一个数 \(X\)\(F[X]=x\times 10^{cnt[F[X/x]]}+F[X/x]\),其中 \(cnt\) 计算一个数的位数,\(x\)\(X\) 的最小质因数 \(v[X]\),可用线性筛 \(O(n)\) 求出,另外,\(F[i]\) 的位数过大,不能直接计算,可以预处理出 \(F[X]\) 的位数,即 \(c[i]\)\(F[i]\) 的位数,则:\(c[i]=cnt[v[i]]+c[i/v[i]]\),然后再预处理 \(10,100,1000,\dots\) 的取余即可

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

代码

// Problem: 牛牛的“质因数”
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30771/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=4e6+5,mod=1e9+7;
int n,m,prime[N],v[N],a[N],b[N],c[N],d[N];
int p[]={1,10,100,1000,10000,100000,1000000};
void primes(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(v[i]==0)
		{
			v[i]=i;
			prime[++m]=i;
		}
		for(int j=1;j<=m;j++)
		{
			if(i>n/prime[j]||v[i]<prime[j])break;
			v[i*prime[j]]=prime[j];
		}
	}
}
int main()
{
    cin>>n;
    primes(n);
    for(int i=1;i<N;i++)a[i]=a[i/10]+1;
    LL res=0;
    d[0]=1;
    for(int i=1;i<N;i++)d[i]=(1ll*d[i-1]*10)%mod;
    for(int i=2;i<=n;i++)
    {
        c[i]=a[v[i]]+c[i/v[i]];
    		b[i]=(1ll*v[i]*d[c[i/v[i]]]+1ll*b[i/v[i]])%mod;
    	res+=b[i];
    }
    cout<<res%mod;
    return 0;
}

J.牛牛想要成为hacker

题目描述

在算法竞赛中"hack"一般指用一组测试数据触发程序的缺陷,从而导致本来通过题目的AC代码无法通过该测试数据。
一般情况见得比较多的是用hack数据导致别人WA掉,当然也有一些会导致原本的AC代码TLE和MLE。

牛牛在一些简单的练习题时遇到了这样一个问题。
给定一个大小为n的数组\(a(1 \leq a_i \leq 10^9)\),然后请你判断数组元素是否能够从中选出三个组成一个三角形。

牛牛发现AC通过的代码中有这样一种暴力逻辑,该逻辑的伪代码如下。

FOR i = 1 ... n
    FOR j = i + 1 ... n
        FOR k = j + 1 ... n
            IF isTriangle(a[i],a[j],a[k])
                print("yes")
                EXIT
            END IF
        END FOR
    END FOR
END FOR
print("no")
EXIT

其实就是三重循环枚举数组的三个元素,检查是否为三角形。这段代码很取巧的地方在于它存在一种“短路”逻辑,一旦发现存在三角形就立刻终止程序。
这样在随机数据下其实很容易发现三角形,所以如果数据纯随机,显然这就是一段AC代码。

牛牛当然知道这个代码很明显就存在缺陷,如果数据构造的好的话应该可以卡TLE,但是牛牛发现,他并不会构造出能够hack这个暴力算法的数据,所以他请你来帮他。

我们以这段程序调用isTriangle的次数作为时间复杂度的计算依据,请你构造数据hack这段暴力程序,使它TLE掉。

输入描述:

第一行输入一个正整数\(n(3 \leq n \leq 10^5)\)表示需要你构造的数组大小。

输出描述:

输出\(n\)个正整数,正整数的范围在\([1,10^9]\)之间,要求该暴力程序在运行过程中调用isTriangle函数的次数不得少于\(min(C_n^3,n^2\left \lfloor log_2n \right \rfloor)\)

示例1

输入

3

输出

2 2 2

说明

当n=3时题目要求小w的程序调用isTriangle函数的次数不得少于1次,所以输出任意的3个正整数都能符合条件。

示例2

输入

10

输出

1 2 4 8 16 32 64 128 256 512

说明

由于任何三个数字都无法组成三角形,所以会扫描到最后一组,达到最大复杂度,一共调用了120次isTriangle函数。

解题思路

构造

考虑使用斐波那契数列来构造:任意三个数不能形成三角形的最慢的数列,当某个数大于 \(1e9\) 时停止构造,后面全部补 \(1\),这样前面的斐波那契大约有 \(40\) 来个,当三个数都为 \(1\) 时才形成三角形,即至少要枚举 \(40n^2\) 次,满足题目要求

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

代码

// Problem: 牛牛想要成为hacker
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30771/J
// 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=1e5+5;
int a[N];
int n;
int main()
{
    cin>>n;
    a[0]=1;
    a[1]=2;
    int i=2;
    while(a[i-1]+a[i-2]<=1e9)a[i]=a[i-1]+a[i-2],i++;
    for(int j=i;j<N;j++)a[j]=1;
    for(int i=1;i<=n;i++)cout<<a[i]<<' ';
    return 0;
}
posted @ 2022-03-23 00:15  zyy2001  阅读(52)  评论(0编辑  收藏  举报