zoukankan      html  css  js  c++  java
  • 数学杂题泛刷

    一个星期抽时间做了一些数学题,整理一下,内容有些杂乱

    大部分是莫比乌斯反演基本套路

    以及一些基础数论知识和奇奇怪怪题的奇奇妙妙做法(雾,我这么菜能做出什么奇奇怪怪的题


    CF1423J Bubble Cup hypothesis

    之前打过的 ACM 模拟赛题目,没有补……

    考虑从两个特殊条件入手:

    1:(P(2)=m)
    2:该多项式任意系数 x 有:(0leq xleq 7)

    由性质 (2) 想到 (8) 进制

    将多项式在 (P(2)) 处展开

    [P(2)=a_0+a_12^1+a_22^2+a_32^3+a_42^4+dots+ ]

    (P(2)) 进行分组得

    [P(2)=(a_0+8a_3+16a_6+dots) imes2(a_1+8a_4+16a_7+dots) imes4(a_2+8a_5+16a_8+dots) ]

    因为每个系数取值为 ([0,7])

    所以原题所求等价于求解:

    [x+2y+4z=m ]

    不定方程解的个数

    对于 (x+2y=m),解的个数有 (lfloor frac{m}{2} floor+1)

    那么考虑扩展至 (x+2y+4z=m)

    解的个数有

    [(lfloorfrac{m}{4} floor+1)(lfloorfrac{m}{2} floor+1)-lfloorfrac{m}{4} floor imes(lfloorfrac{m}{4} floor+1) ]

    就行了

    link

    P1445 [Violet]樱花

    求解方程

    [frac{1}{x}+frac{1}{y}=frac{1}{n!} ]

    (那个十字相乘法也太离谱了,正常人谁会往那想

    对于 y 一定满足这样的形式:

    [y=n!+k(kinmathbb{Z}) ]

    那么有:

    [frac{1}{x}+frac{1}{n!+k}=frac{1}{n!} ]

    去分母

    [n!(n!+k)=xk ]

    最终:

    [frac{(n!)^2}{k}+n!=x ]

    所以我们只要统计出 ((n!)^2) 有多少个因子即可

    [x=p_{alpha_1}^{eta_1}p_{alpha_2}^{eta_2}p_{alpha_3}^{eta_3}p_{alpha_4}^{eta_4}dots p_{alpha_k}^{eta_k} ]

    因子个数为

    [(eta_1+1)(eta_2+1)dots(eta_k+1) ]

    当因为是阶乘,如果暴力的话是 (O(nsqrt n)),预处理素数,然后用素数筛,再开一把 O2 勉强能过

    这里给出对于 (n!) 这种阶乘的每个(eta)的求法

    [eta=sum_{k=1,p^kleq n}lfloorfrac{n}{p^k} floor ]

    link

    P3327 [SDOI2015]约数个数和

    ( au(d)) 为 x 的约数个数,给定 (n,m),求

    [sum_{i=1}^nsum_{j=1}^m au(ij) ]

    首先对 ( au(x)) 函数来说,有如下性质

    [ au(xy)=sum_{i|x}sum_{j|y}[gcd(i,j)=1] ]

    带回原式

    [sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|j}[gcd(x,y)=1] ]

    [sum_{x=1}^{n}sum_{y=1}^{m}lfloorfrac{n}{x} floorlfloorfrac{n}{y} floor[gcd(x,y)=1] ]

    [sum_{d=1}^{d=min(n,m)}mu(d)sum_{x=1}^{n}sum_{y=1}^{m}lfloorfrac{n}{x} floorlfloorfrac{n}{y} floor[d|gcd(x,y)] ]

    [sum_{d=1}^{d=min(n,m)}sum_{x=1}^{n}lfloorfrac{n}{x} floor[d|x]sum_{y=1}^{m}lfloorfrac{m}{dy} floor[d|y] ]

    [sum_{d=1}^{d=min(n,m)}sum_{x=1}^{lfloor frac{n}{d} floor}lfloorfrac{n}{dx} floorsum_{y=1}^{lfloor frac{m}{d} floor}lfloorfrac{m}{dy} floor ]

    可以发现后面两个求和记号是可以预处理的

    嗯然后直接整除分块即行

    link

    好吧我们似乎遗忘了什么东西,对就是一开始给出的关于 ( au) 的式子。

    太阴间了,看不懂这个神奇的映射

    P3768 简单的数学题

    简单数学题呵呵……

    (取模就能烦死你

    所以我们先不考虑取模

    [sum_{i=1}^{n}sum_{i=1}^{n}ijgcd(i,j) ]

    [sum_{p=1}^{n}sum_{i=1}^{n}sum_{i=1}^{n}ijp[gcd(i,j)=p] ]

    [sum_{p=1}^{n}p^3sum_{i=1}^{lfloorfrac{n}{p} floor}sum_{j=1}^{lfloorfrac{n}{p} floor}ij[gcd(i,j)=1] ]

    [sum_{p=1}^{n}p^3sum_{i=1}^{lfloorfrac{n}{p} floor}sum_{j=1}^{lfloorfrac{n}{p} floor}ijsum_{d|gcd(i,j)}mu(d) ]

    [sum_{p=1}^{n}p^3sum_{d=1}^{n}mu(d)sum_{i=1}^{lfloorfrac{n}{p} floor}i[d|i]sum_{j=1}^{lfloorfrac{n}{p} floor}j[d|j] ]

    [sum_{p=1}^{n}p^3sum_{d=1}^{n}mu(d)d^2sum_{i=1}^{lfloorfrac{n}{dp} floor}isum_{j=1}^{lfloorfrac{n}{dp} floor}j ]

    (F(x)=sum_{i=1}^{x}i)

    所以上式为

    [sum_{p=1}^{n}p^3sum_{d=1}^{n}mu(d)d^2F^2(lfloorfrac{n}{dp} floor) ]

    再交换一波求和顺序

    [sum_{T=1}^{n}F^2(lfloorfrac{n}{T} floor)sum_{p|T}p^3left(frac{T}{p} ight)^2mu(frac{T}{p}) ]

    [sum_{T=1}^{n}F^2(lfloorfrac{n}{T} floor)T^2sum_{p|T}p imesmu(frac{T}{p}) ]

    可以发现后面的求和记号那部分正好是(mu*id=phi)

    所以

    [sum_{T=1}^{n}F^2(lfloorfrac{n}{T} floor)T^2phi(T) ]

    可以发现这个式子后面两部分是个啥我们不知道

    但前面那部分是可以用整除分块优化掉的,也就是说我们只要能在一个合理的复杂度内求出后面那部分的前缀和,就可以切掉这道题。

    仔细观察后面那部分似乎是 (id^2phi),两个积性函数,看起来似乎可以用杜教筛

    杜教筛有点忘了,这里简单复习一下

    若有数论函数(g,f)满足

    [sum_{i=1}^{n}sum_{d|i}g(d)f(frac{i}{d})=sum_{i=1}^{n}g(i)S(lfloorfrac{n}{i} floor) ]

    则有

    [sum_{i=1}^{n}(f*g)(i)=sum_{i=1}^{n}g(i)S(lfloorfrac{n}{i} floor) ]

    设所求 (f(x)=x^2phi(x)=id^2phi(x))(S(x)=sum_{i=1}^{x}f(x))

    (f)函数不是(id^2*phi)(id^2phi)(应该不会有人和我一样傻逼以为是 $id $卷 (phi),然后直接构造了个 (g=I) 卷上去了吧,不会吧不会吧

    摊牌了,后面构造 (g) 函数为 (id^2),你这么考虑

    [sum_{d|n}d^2phi(d)g(frac{n}{d}) ]

    [sum_{d|n}d^2phi(d)left(frac{n}{d} ight)^2 ]

    等价于

    [n^2sum_{d|n}phi(d) ]

    后面那部分又相当于(I*phi=id),所以(f*g=id^3)

    直接给出立方前缀和公式,(sum_{i}^ni^3=left(frac{(n imes (n+1))}{2} ight)^2)

    再给出平方前缀和公式,(sum_i^ni^2=frac{n imes(n+1) imes(2 imes n+1)}{2})

    所以杜教筛直接求就完事了

    (一点也没有完事,里面的取模能烦死你,每做一步乘法运算都要取模一次,真是吐了

    link

    P1829 [国家集训队]Crash的数字表格 / JZPTAB

    形式化地

    [sum_{i=1}^{n}sum_{j=1}^{m}operatorname{lcm}(i,m) ]

    [=sum_{i=1}^{n}sum_{j=1}^{m}frac{i imes j}{gcd(i,j)} ]

    看到 (gcd),我们直接套路

    最后大概能化成这样

    [sum_{p=1}^{min(n,m)}psum_{i=1}^{lfloorfrac{n}{p} floor}sum_{j=1}^{lfloorfrac{m}{p} floor}ij[gcd(i,j)=1] ]

    单独提出来后面连个求和记号

    [sum(x,y)=sum_{i=1}^{x}sum_{j=1}^{y}ij[gcd(i,j)=1] ]

    [=sum_{i=1}^{x}sum_{j=1}^{y}ijsum_{d|gcd(i,j)}mu(d) ]

    [=sum_{d=1}^{min(x,y)}mu(d)sum_{i=1}^{x}i[d|i]sum_{j=1}^{y}j[d|j] ]

    (F(x)sum_{i=1}^{x}i)

    [=sum_{d=1}^{min(x,y)}mu(d)d^2F(lfloorfrac{x}{d} floor)F(lfloorfrac{y}{d} floor) ]

    (艹,我当时犯傻逼一直把后面两个求和符号消成(lfloorfrac{x}{d} floor imeslfloorfrac{y}{d} floor),然后就导致一直求错。

    然后这个东西很明显可以进行整除分块,范围很小也不需要杜教筛

    和前面的式子拼一下

    [sum_{p=1}^{min(n,m)}p imes sum(lfloorfrac{x}{d} floor,lfloorfrac{y}{d} floor) ]

    嗯就这然后这玩意也可以整除分块……

    复杂度是 (O(n))

    P2303 [SDOI2012] Longge 的问题

    很明显这是个傻逼题,连我这种菜逼都会。。。

    所以我们来研究一下那个比较牛逼的做法

    [sum_{i=1}^{n}gcd(i,n) ]

    [sum_{d|n}sum_{i=1}^{frac{n}{d}}d[gcd(i,frac{n}{d})=1] ]

    这玩意就是一个傻逼欧拉函数而已再加一个因子个数

    [sum_{d|n}dphi(frac{n}{d}) ]

    怪麻烦的,不想证了,挂个我觉得写得不错的链接想康的自己康吧 link

    P3312 [SDOI2014]数表

    这个题就跟前几个题不大一样了

    [sum_{i=1}^{n}sum_{j=1}^{m}sigma(gcd(i,j))[sigma(gcd(i,j))leq a] ]

    (T) 组数据,(T,n,m) 的范围都在十万级别,(a) 的取值为 (operatorname{int}) 型整数

    根据经验,应该化成一个乘除分块的形式。所以我们就推推推就行了。

    最后我是化成了

    [sum_{T=1}^{min(n,m)}T imeslfloorfrac{n}{T} floorlfloorfrac{m}{T} floor ]

    然后我就不会做了

    看了眼题解之后才明白需要与数据结构结合一下

    根据 (sigma*mu=id),上式可化为

    [sum_{T=1}^{min(n,m)}lfloorfrac{n}{T} floorlfloorfrac{m}{T} floorsum_{d|T}sigma(d)muleft(frac{T}{d} ight) ]

    首先前面的部分可以整除分块,然后考虑在 (a) 的限制下,我们应该如何处理后半部分。

    [sum_{d|T}sigma(d)muleft(frac{T}{d} ight)[sigma(d)leq a] ]

    可以考虑将所有查询离线处理,然后按照 a 的大小进行排序,增量维护每个 T 后半部分。具体来说,当有一个 x 满足:(x leq a),我们枚举 x 的倍数 (P),在对应的树状数组中添加 (sigma(x)muleft(frac{P}{x} ight)),以此类推即可。

    至于为什么用树状数组,因为我们整除分块之后需要快速查区间和,显然树状数组非常合适。

    至于取模什么的就不多说了,和之前的差不多。

    (代码中有几处我认为比较细的地方,一处是线性筛处理约数和,另一处是一次询问的树状数组

    (还有中间的取模不知道为什么会挂掉,好迷呀

    inline int primes(int n)
    {
    	vis[1] = 0;
    	sum[1] =1 ;
    	mu[1] = 1;
    	for(int i=2;i<=n;i++)
    	{
    		if(!vis[i])
    		{
    			vis[i] = i;
    			prime[++tit] = i;
    			cnt[i] = sum[i] = i + 1;
    			mu[i] = -1;
    		}
    		for(int j=1;j<=tit;j++)
    		{
    			if(prime[j] > vis[i] || i * prime[j] > n) break;
    			vis[i * prime[j]] = prime[j];
    			if(i % prime[j] != 0) sum[i * prime[j]] = sum[i] * sum[prime[j]],cnt[i * prime[j]] = 1 + prime[j];
    			else 
    			{
    				sum[i * prime[j]] = sum[i]/cnt[i] * (cnt[i] * prime[j] + 1);
    				cnt[i * prime[j]] = cnt[i] * prime[j] + 1;
    				break;
    			}
    			mu[i * prime[j]] = -mu[i];
    		}
    	}
    	
    	for(int i=1;i<=n;i++) sig[i] = (pii){sum[i],i};
    }
    

    鸣谢 xmz 的筛法

    link

    inline int query(int l,int r)
    {
    	l--;
    	int Ans = 0;
    	while(r > l) Ans+=tree[r],r -= lowbit(r);
    	while(l > r) Ans-=tree[l],l -= lowbit(l);
    	return Ans % mod;
    }
    

    算了,这里证一下那个神奇的单常数树状数组询问。(虽然也是嫖的

    (r) 在二进制下有 (x) 位, (l-1)(y) 位,最长公共后缀有 (z) 位。如果 z ( e 0),那么 (x=y)(x-z) 位必然为 (1)(y-z) 位必然为 (0)。那么在 (r)(lowbit) 的过程中,在减到 (x-z) 位之前 (r) 恒大于 (l-1),减掉 (x-z) 位之后,(rleq l-1)。此过程对于 (l-1) 同理。所以就避免了减去重复部分的常数。(我突然感觉自己很有病,树状数组常数都这么小了,还想怎么样

    CF338D GCD Table

    二轮集训的时候讲过的一道题

    对于 (j) 来说,应满足

    [jequiv0pmod{a_1}$$$$jequiv-1pmod{a_2} ]

    [jequiv-2pmod{a_3}]

    [ldots$$$$jequiv1-kpmod{a_k} ]

    所以如果这个题有解,那么一定满足这个同余方程组,所以我们先求出这个同余方程来。

    注意,这是个必要而不充分的条件,也就是说,对该方程的一个解,其可能并不满足题意……

    对于 (i) 来说,其必然是 (operatorname{lcm(a_1,a_2,a_3,cdots,a_k)}) 的倍数。

    这里证明一下 (i)(operatorname{lcm(a_1,a_2,a_3,cdots,a_k)}) 时最优。这里记 (M = operatorname{lcm(a_1,a_2,a_3,cdots,a_k)})

    如果当i并不为M,可以设i = kM,那么有

    [gcd(i,Ans)=a_1 ]

    这里的 (Ans) 时我们求解 (Excrt) 所得到的解,如果当 (i = kM) 时,则说明 (Ans) 必须满足只有一个(a_1),而当 (i=M) 时,(Ans) 可以有多个 (a_1),则 (i=kM) 求出解的解一定被包含在 (i=M) 中,所以取 (i=M) 最优。

    那对于后面的 (Ans) 来说,既然已经取了 (i = M),那么你递归 (gcd) 的时候一定会模去一个 i,那后面 (Ans) 并不需要扩大,因为那没有意义。

    (一开始并没有往 (gcd) 同除 (a_i) 上考虑,而是直接考虑展开递归,然后对一对参数求解 exgcd 然后就发现并没有什么用……中间还推错式子了……

    最后记得检验,因为 excrt 部分只满足必要性

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define int long long
    #define ri register int
    #define pb push_back
    #define db double
    #define pii pair<int,int>
    #define ill long long
    #define fi first
    #define sc second
    
    const int np = 1e5 + 5;
    
    template<typename _T>
    inline void read(_T &x)
    {
    	x=0;char s=getchar();int f=1;
    	while(s<'0'||s>'9') {f=1;if(s=='-')f=-1;s=getchar();}
    	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
    	x*=f;
    }
    
    inline int Mul(int x,int y,int mod)
    {
    	int z=(long double)x/mod*y;
    	int res=(unsigned int)x*y-(unsigned int)mod*z;
    	return (res%mod+mod)%mod;
    }
    
    inline int exgcd(int a,int b,int &x,int &y)
    {
    	if(!b){x= 1,y = 0;return a;}
    	int d = exgcd(b,a%b,x,y);
    	int t = x;
    	x = y , y = t - (a/b) * y;
    	return d;
    }
    int a[np],M;
    
    inline int gcd(int a,int b)
    {
    	if(b == 0) return a;
    	else return gcd(b, a % b);
    }
    
    namespace Excrt{
    	int a_[np],b[np];
    	int Main(int n)//exgcd 部分打错了一万次
    	{
    		int Ans = b[1];
    		int m = a_[1];
    		for(int i=2;i<=n;i++)
    		{
    			int k1(0),k2(0);
    			int ans = (((b[i] - Ans)%a_[i])+a_[i])%a_[i];
    			int g = exgcd(m,a_[i],k1,k2);
    			if(ans % g != 0) return -1;
    			int x = Mul(k1,ans/g,a_[i]);
    			Ans += m * x;
    			m *= a_[i]/g;
    			Ans = (Ans + m) % m;
    		}
    		if(!Ans) Ans += m;
    		return Ans;
    	}
    };
    
    signed main()
    {
    	int n,m,k;
    	read(n);
    	read(m);
    	read(k);
    	
    	for(int i=1;i<=k;i++) read(a[i]);
    
    	int lcm = a[1];
    	for(int i=2;i<=k;i++)
    	{
    		lcm = lcm/gcd(lcm,a[i])*a[i];
    		if(lcm > n)
    		{
    			cout<<"NO";
    			return 0;
    		}		
    	}
    	for(int i=1;i<=k;i++)
    	{
    		
    		Excrt::b[i] = (a[i]-i + 1);
    		while(Excrt::b[i] < a[i])
    		{
    			Excrt::b[i] += a[i]; 
    		}
    		Excrt::b[i] %= a[i];
    		Excrt::a_[i] = a[i];
    	}
    	
    	int j_ = Excrt::Main(k);
    	if(j_ == -1)
    	{
    		cout<<"NO";
    		return 0;
    	 } 
    	if(j_ > m) 
    	{
    		cout<<"NO";
    		return 0;
    	}
    	if(j_ + k -1 > m)
    	{
    		cout<<"NO";
    		return 0;
    	}
    	
    	for(int i=j_;i<=j_ + k - 1;i++)
    	{
    		if(gcd(lcm,i) != a[i - j_ + 1])
    		{
    			cout<<"NO";
    			return 0;
    		}
    	}
    	cout<<"YES";
    }
    

    到此完结,可能以后还会有三篇数学泛刷

    内容大概就是组合数学、线性代数与期望概率以及阴间数学题。。。。

  • 相关阅读:
    LeetCode 4 :Majority Element
    LeetCode 3 :Min Stack
    Oracle操作4
    plsql安装教程
    java Date与String互相转化
    Oracle操作3
    Oracle操作2
    Oracle操作
    Oracle11g修改密码
    Visual Studio2013完全卸载
  • 原文地址:https://www.cnblogs.com/-Iris-/p/15350219.html
Copyright © 2011-2022 走看看