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

比赛链接

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

I.牛牛的“质因数”

题目描述

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

输入描述:

仅一行一个正整数 n(2n4×106)

输出描述:

仅一行, 表示答案对 109+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

解题思路

筛质数

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

  • 时间复杂度: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(1ai109),然后请你判断数组元素是否能够从中选出三个组成一个三角形。

牛牛发现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(3n105)表示需要你构造的数组大小。

输出描述:

输出n个正整数,正整数的范围在[1,109]之间,要求该暴力程序在运行过程中调用isTriangle函数的次数不得少于min(Cn3,n2log2n)

示例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 时才形成三角形,即至少要枚举 40n2 次,满足题目要求

  • 时间复杂度: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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16042259.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示