专题[vjudge] - 数论0.1

时间:2023-03-10 07:54:54
专题[vjudge] - 数论0.1

专题[vjudge] - 数论0.1

web-address : https://cn.vjudge.net/contest/176171

A - Mathematically Hard

题意就是定义一个函数S.其中S(x)=sqr(1~x中与x互质的数的个数).

显然,这里要运用到Euler函数(即φ函数,题后已给出).那么,我们计算出5*10^6以内的phi后,计算一个前缀平方和就行了.

B - Ifter Party

题意就是让你求一个数大于L的因数,并把它们升序输出.比较水,但是容易PE.

C - Eid

题意就是求n个数的lcm(需要高精度).那么,通过gcd求lcm的方法.

D - Trailing Zeroes (I)

题意就是n在几个进制下,末尾为0.

显然,假设当前是K进制,如果n%K==0,那么显然,这个进制是可行的.

那么题目就转为了求K的因子个数(除1以外).然后用唯一分解定理就可以了.

E - Digits of Factorial

假设当前是十进制,那么n!的位数就是log10(n!).根据log10的性质,得

log10(!n)=log10(1)+log10(2)+log10(3)+...+log10(n).

那么我们可以先预处理出前缀和.

由于我们要的是n!在base进制下的位数,所以我们要换底.

(ans=logbase(1)+logbase(2)+logbase(3)+...+logbase(n))

即ans=(int)(f(n)(即上面的前缀和)/log10(base)).(这应该是高数必修1的内容)

F - Efficient Pseudo Code

题意就是求n^m的因数和%TT.

我们运用唯一分解定理,将K=n^m分解质因数.

则,K的因子和为π(i=1,因子种数)p[i]^0+p[i]^1+p[i]^2+...+p[i]^x.

我们发现后面这一串是个等比数列,可以O(1)求出,但是需要用到逆元.

G - Combinations

题意就是求n!/(k!*(n-k)!).不过也需要用到逆元.

H - How Many Points?

题目转化以后就是求gcd,水.

I - Trailing Zeroes (II)

题目就是求一个数的后缀连续0有几个.

那么我们只需要知道这个数的因数5的个数就行了(显然,根本不需要考虑2).

那么,我们只要对原来的东西进行一些处理就行了.

J - A New Function

题目就是求σ(i=1,n)i的因数和(除去1和本身).

对于这一题,我们肯定不能通过枚举i(1~n)来算.我们要枚举每一个在(2~sqrt(n))的数.

假设当前枚举了一个i.则:

在i+1~n这个范围内,会出现若干个i的倍数.

到底有多少个?cnt=n/i-(i+1)+1.

因为我们假设另一个因数大于i,所以L=i+1,那么R最多就是R/i了,则这一步ans+=cnt*i.

同时,我们要计算另一个因数.我们刚才已经算过了,长度为cnt,且是公差为1的等差数列.

ans+=cnt*(n/i+(i+1)).当然,最后还要加上一个i,不然i会被漏掉计算1次.

为什么这样是正确的呢?我们既保证了每一个数都是被他前面的数更新到的,也保证了每个数都能被不遗漏地更新到.

K - Trailing Zeroes (III)

题意就是给你一个数Q,然后问你是否存在一个数N,N!末尾恰好有Q个连续的"0".

那么,我们设f(n)为n!末尾有几个连续的掉"0".

那么,这个函数从1~n一定是一下增加,一下不变.由于Q比较大,空间比较紧,所以我们肯定要隔着几个数存一个.

而由于N!中,末尾0的个数由因数1~N中因数5的个数来决定的,我们可以分成每100个或200个一块.

然后,在询问中,我们通过二分查找能知道n在那一段.然后在这一段内,可以通过O(段的大小*(平均)因数5的个数)的时间处理出答案.

L - Bank Robbery

题意就是给你X=A-B的值,告诉你B=A/10(向下取整),让你求满足的A,使得A-B是A的前缀.

显然,我们可以进行分类讨论.

1.如果10B=A,则:X=A-B=9B

那么如果X%9==0,则我们就可以算出A,B的值,必定有解.

2.如果10B+K0=A,则X=A-B=9B+K0

由于,B=A/10(向下取整)

A/10(非向下取整)=B+K(0.0<K<1.0且K是(0.1*整数)).

所以A=B+K0(0<K<10且K是整数).

那么,我们只需要枚举K=1~9,然后判断(X-K)是否被9整除就行了.

M - Help Hanzo

题意就是给你一段区间L,R,问区间内有多少质数,其中R-L<=100000,1<=L<=R<=1e2.

这一题刚好满足二次筛的性质.由于L,R<=1e12.那么,我们只要筛出1e6的素数,然后再用这些素数去筛L,R,保证合数都能筛到.

我们只需要将区间前一一下就行了.复杂度理论上很高,但是实际上远远达不到.

N - Fantasy of a Summation

题意就是算出:

(sigma(i=1,k)sigma(j=1,n)A[j])%TT

由于每个A[i]被计算到的次数是相同的,可以通过总次数/n得出.

总次数=(n^k).所以每个数都被计算(n^(k-1))次.

所以ans=sum(A[i])*n^(k-1).显然需要用到快速幂和逆元.

O - Large Division

高精模,水题.

P - Finding LCM

题意就是给你3个数a,b,L,求是否存在最小的c,使得lcm(a,b,c)=L.

显然,这题需要用到唯一分解定理,我们先把问题变为:lcm(x=lcm(a,b),c)=L

那么,我们无非对x和L进行质因数分解.如果有解,那么,x的所有质因数肯定都被L包含了,且这个质因数在L的个数必定不小于在x(语文不好,请谅解).

如果是有解的,我们计算解,对于每一个L的质因数,只需要ans*=(powL[目前质因数]-powx[目前质因数])就行了.

Q - Mysterious Bacteria

题意就是求一个数n,存在n=x^p,要求这个p最大.

还是运用唯一分解.

n=π(pi^xi).

那么,如果存在n=x^p(且p最小)那么,p=gcd(xi).

不过,我们需要注意n是负数的情况(坑).

R - Harmonic Number

题意就是求给定函数的值.我们初始的想法就是O(n)算出f(n)然后记录一下.

然后发现会MLE.所以,我们就要隔几个数记录一个数,我取的间隔是100.然后如果n%100!=0,则在长度为100的区间内算一算就行了.

S - Pairs Forming LCM

题意就是给出一个数n,求sigma(i=1,n;j=i,n)lcm(i,j)=n.

突破口还是先把n分解质因数——n=p1^x1*p2^x2*p3^x3*……*pk^xk

由于lcm(i,j)=n,所以i,j中必有一个数x,满足n具有的质因数,x必有,且指数与n相同.

同时,i,j不能具有n没有的质因数.

显然,我们可以枚举n的每一个质因数,设为pi,指数为xi.那么,有(xi*2+1)种合法的且构造出的n,m不同的方案.

根据乘法原理,将每一个质因数的(xi*2+1)相乘就行了。最后要减去计算n,n时重复计算了一个.

T - Harmonic Number (II)

题意就是求sigma(i=1,n)n/i(向下取整).这题题面与R题略有不同,但是解法上是大有不同.

由于i的递增,n/i的值是单调不升的.更确切的说,应该是一段降,一段不变,这样循环的.

那么,由于我们可以在sqrt(n)时间内处理出1~sqrt(n)范围内所有数的n/i的值.

又因为,如果i>sqrt(n),则n/i<sqrt(n),那么n/i的取值就只有sqrt(n)种,那我们又可以用sqrt(n)的时间处理出剩下的数里面的n/i的值.

前面一类怎么计算?

for (int i=1; i<=sqrt(n); i++) ans+=n/i;

后面一类怎么计算?

for (int i=1; i<=sqrt(n); i++) ans+=(n/i-n/(i+1))*i;

显然,sqrt(n)会被计算到两次,所以最后ans-=(int)sqrt(n);

U - Goldbach`s Conjecture

由于1e7里的质数只有670000个左右,所以,我们之间枚举其中一个质数,然后判断差是不是质数就行了,水过.

V - Sum of Consecutive Integers

题目就是给你一个数n,问你能分成几种长度大于1的等差数列.

本来想枚举等差数列的长度,然后发现被卡了.

我们现将这个式子列出:(a+a+len-1)len=2n

其中n是首项,len是长度.

将上式变形——2a=2n/len-(len-1)

由于2a必为偶数,所以2n/len-(len-1)必为偶数.

假如len是奇数,则2n/len为偶数,2n/len-(len-1)就是偶数,偶数*奇数=偶数,说明对于每一个奇数的len且len可以整除2n/len,都有一种方案.

假如len是偶数,则2n/len−(len−1)=2∗a;因为(len−1)为奇数,2∗a1为偶数,所以2n/len为奇数.令t为上下含有的因子2的个数,上下含有2的个数必定相等.

令t=2^t,那么得到(2n/t)/(len/t),令u=len/t,那么u就是n的奇数因子,又因为每个len的值会一一对应一个答案的等差数列,所以我们相当于算出要u的个数(u和len是等效等价的).

所以即使当len为偶数的时候是通过求n的奇数因子而求得.

所以,对于任意数n,只有求出奇数因子个数就行了,最后减去还要减1(相当于len=1时的方案).

W - Leading and Trailing

题意就是给你n和k,求出n^k的前三位和后三位.

这题我们需要用到log的妙用.

如果x=log10(y)=a(x的整数部分)+b(x的小数部分)

则10^a*10^b=y.

那么,10^a表示什么呢?10^b又表示什么呢?

举个例子:y=369123,则x=5.567171106864250556407381944533,a=5,b=0.567171106864250556407381944533.

而10^a=100000,10^b=3.6912300000000000000000000000001(精度问题,请无视)

多试几个数,我们会发现,10^b*100就是y的前三位.

那么,现在我们求的是n^k的前三位.

因为log10(n^k)=klog10(n),所以,我们先算出b=klog10(n)-trunc(klog10(n))的值,然后再计算出10^b*100就行了.

求后三位就很水了,但是要注意,如果是024什么的,就要输出024,而不是24.

X - LCM from 1 to n

题意就是给你一个n,求lcm(i)(i=1,n).

显然,如果数据小的话,我们枚举1~n中每一个质数x,然后设x^p<=n且x^(p+1)>n,那么lcm*=x^p.

但是问题是,我们空间要炸(我们记录不了所有素数).

此时,我们要压缩空间.这么压缩?我们可以用位图记录某个数是否为素数的信息.将32个数作为1个二进制数,在十进制下放在一个数组变量内,然后坐到o1查询更新,还节省了32倍的空间.

解决了空间问题,我们在回到原问题.我们只知道这个做法是不够的,我们要知道怎样实现最好.

其实,最后的答案无非是这样的:

2^x1*3^x2*5^x3*7^x4*......而其中,x1>=x2>=x3>=x4......

也就是说,越大的质数,其指数越小.

我们先记录一个质数的前缀积(M[1]=2,Mul[2]=2*3,Mul[3]=2*3*5,Mul[4]=2*3*5*7......)

显然,这满足二分的条件,我们可以二分查找.

每一次查找k,查找一个数i,使得p[i]^k<=n且(p[i+1])^k>n.也就是说,我们保证p[i+1]只被乘到应该乘到的次数(k-1次).

查找到i后,ans*=Mul[i],相当于p[1]~p[i]都被乘了1次.

显然,总共要二分查找log2(n)次,因为2^log2(n)=n.

Y - Politeness

并没有A掉......

Z - Strange Game

并没有A掉......

-------------------------------------------------------Updating...Please Wait-------------------------------------------------------

题意是n个人轮流操作,每次要用k种字符,每种字符有inf个,每人每次构造两个长度均为l且恰好有m个对应位置不同的字符串,不考虑这两个字符串先后顺序(也就是要去重),不能和之前人构造的一样,问谁最先构造不出来.

这题乍一看很复杂,但是静下心来想还是可做的.

我们从l个位置选出m个作为出现差异的位置,总共有C(l,m)种方案.

然后,第一个串中,每个位置都有k种选择,第二个串中,只有m个位置有k-1种选择(其余位置只有1种选择).

又因为要去重,所以答案就是((C(l,m)*k^l*(k-1)^m)/2)%n+1

而上式中,k^l*(k-1)^m/2的值是能够很快求出的.

那C(l,m)呢?显然,C(l,m)=l!/(m!*(l-m)!).

但是,我们能尽量减少除法就减少.

我们可以分别算出1~l,1~m,1~l-m中每个质因数的个数,假设存在a,b,c数组内(实际上我们并不要开这个数组).

那么,我们算出π(i=1,cnt(质数个数))quickly_power(pi,ai-bi-ci)%n就行了.

当然,如果m=0时,我们只要求出k^l%n的值就行了.[lol]