组合数学与数论函数专题

组合数学专题

专题简介

本专题包含了一些组合数学中常见的套路和方法,如拉格朗日插值,动态规划,容斥原理,狄利克雷卷积,线性筛,杜教筛 等等.

目录

  1. 2018 四川省赛GRISAIA (数论分块)
  2. HDU 6428 Calculate (狄利克雷卷积,线性筛)
  3. BZOJ4559 成绩比较 (动态规划,拉格朗日插值)
  4. BZOJ 2633 已经没有什么好害怕的了 (容斥森林,动态规划)
  5. BZOJ 3930 选数 (容斥原理,动态规划)
  6. 徐州网络赛 D Easy Math (积性函数,线性筛)
  7. NWERC2015 Debugging (动态规划,数论分块)

四川省赛 GRISAIA

问题描述

∑i=1n∑j=1in%(i∗j)\sum_{i=1}^{n}\sum_{j=1}^{i}{n \% (i * j)}i=1nj=1in%(ij),其中1≤n≤10111 \le n \le 10^{11}1n1011

引入的一些性质

⌈nxy⌉=⌈⌈nx⌉y⌉\lceil \frac{n}{xy} \rceil = \lceil \frac{\lceil \frac{n}{x} \rceil}{y} \rceilxyn=yxn
⌊nxy⌋=⌊⌊nx⌋y⌋\lfloor \frac{n}{xy} \rfloor = \lfloor \frac{\lfloor \frac{n}{x} \rfloor}{y} \rfloorxyn=yxn

解法

先对原问题进行变形:

∑i=1n∑j=1in%(i∗j)\sum_{i=1}^{n}\sum_{j=1}^{i}{n \% (i * j)}i=1nj=1in%(ij)

=∑i=1n∑j=1i(n−⌊(nij)⌋∗ij)= \sum_{i=1}^{n}\sum_{j=1}^{i}{(n - \lfloor (\frac{n}{ij}) \rfloor * ij)}=i=1nj=1i(n(ijn)ij)

只需要求:

∑i=1n∑j=1i⌊(nij)⌋∗ij\sum_{i=1}^{n}\sum_{j=1}^{i}{\lfloor (\frac{n}{ij}) \rfloor * ij}i=1nj=1i(ijn)ij

=12∑i=1n∑j=1n(⌊(nij)⌋∗ij)+12∑i=1n⌊ni2⌋∗i2= \frac{1}{2}\sum_{i=1}^{n}\sum_{j=1}^{n}{(\lfloor (\frac{n}{ij}) \rfloor * ij}) + \frac{1}{2}\sum_{i=1}^{n}{\lfloor \frac{n}{i^2} \rfloor * i^2}=21i=1nj=1n((ijn)ij)+21i=1ni2ni2

只需要求:

∑i=1n∑j=1n(⌊(nij)⌋∗ij)\sum_{i=1}^{n}\sum_{j=1}^{n}{(\lfloor (\frac{n}{ij}) \rfloor * ij})i=1nj=1n((ijn)ij)

这里我们就要使用引入的性质了:

=∑i=1n∑j=1n(i∗⌊⌊ni⌋j⌋∗j)= \sum_{i = 1}^{n}\sum_{j = 1}^{n}(i * \lfloor \frac{\lfloor \frac{n}{i} \rfloor}{j} \rfloor * j)=i=1nj=1n(ijinj)

=∑i=1ni∑j=1n(⌊⌊ni⌋j⌋∗j)= \sum_{i = 1}^{n}{i}\sum_{j = 1}^{n}( \lfloor \frac{\lfloor \frac{n}{i} \rfloor}{j} \rfloor * j)=i=1nij=1n(jinj)

记录

f(n)=∑i=1n⌊ni⌋∗if(n) = \sum_{i = 1}^{n}{\lfloor \frac{n}{i} \rfloor} * if(n)=i=1nini

显然

∑i=1n∑j=1n(i∗⌊⌊ni⌋j⌋∗j)=∑i=1ni∗f(⌊ni⌋)\sum_{i = 1}^{n}\sum_{j = 1}^{n}(i * \lfloor \frac{\lfloor \frac{n}{i} \rfloor}{j} \rfloor * j) = \sum_{i = 1}^{n}{i*f(\lfloor \frac{n}{i} \rfloor)}i=1nj=1n(ijinj)=i=1nif(in)

显然f(n)f(n)f(n)的计算可以数论分块,然后上面部分的计算也可以分块.


HDU6428 [Calculate]

知识清单

  1. 欧拉函数
  2. 莫比乌斯函数
  3. 莫比乌斯反演
  4. 狄利克雷卷积
  5. 线性筛

题解

要求计算∑i=1A∑j=1b∑k=1C(ϕ(gcd(i,j2,k3)))\sum_{i = 1}^{A}\sum_{j = 1}^{b}\sum_{k = 1}^{C}(\phi(gcd(i,j^2,k^3)))i=1Aj=1bk=1C(ϕ(gcd(i,j2,k3)))
我们先对式子进行变换,比较套路一步是改为枚举gcdgcdgcd,然后统计gcdgcdgcd出现的次数,即:

=∑d=1ϕ(d)(∑i=1A∑j=1b∑k=1C[gcd(i,j2,k3)=d])= \sum_{d = 1}{\phi{(d)}}{(\sum_{i = 1}^{A}\sum_{j = 1}^{b}\sum_{k = 1}^{C}[gcd(i,j^2,k^3)=d])}=d=1ϕ(d)(i=1Aj=1bk=1C[gcd(i,j2,k3)=d])

对上述式子中的∑i=1A∑j=1b∑k=1C[gcd(i,j2,k3)=d]\sum_{i = 1}^{A}\sum_{j = 1}^{b}\sum_{k = 1}^{C}[gcd(i,j^2,k^3)=d]i=1Aj=1bk=1C[gcd(i,j2,k3)=d]再进行莫比乌斯反演:

g(d)=∑i=1A∑j=1b∑k=1C[gcd(i,j2,k3)=d]g(d) = \sum_{i = 1}^{A}\sum_{j = 1}^{b}\sum_{k = 1}^{C}[gcd(i,j^2,k^3)=d]g(d)=i=1Aj=1bk=1C[gcd(i,j2,k3)=d]

并设G[n]=∑n∣dg(d)G[n] = \sum_{n|d}{g(d)}G[n]=ndg(d)

那么显然有g(n)=∑n∣dμ(dn)G(d)g(n) = \sum_{n|d}\mu(\frac{d}{n})G(d)g(n)=ndμ(nd)G(d)

那么要求的式子可以写成

=∑d=1ϕ(d)g(d)=∑d=1ϕ(d)∑d∣tμ(td)G(t)= \sum_{d = 1}{\phi{(d)}} g(d) = \sum_{d = 1}{\phi{(d)}}\sum_{d|t}\mu(\frac{t}{d})G(t)=d=1ϕ(d)g(d)=d=1ϕ(d)dtμ(dt)G(t)

由于ϕ(x)\phi(x)ϕ(x)μ(x)\mu(x)μ(x)都是积性函数,故将G[t]G[t]G[t]ϕ(d)\phi(d)ϕ(d)的位置做交换,使之形成狄利克雷卷积.

=∑t=1G(t)∑d∣tμ(td)ϕ(d)= \sum_{t=1}G(t)\sum_{d|t}\mu(\frac{t}{d})\phi(d)=t=1G(t)dtμ(dt)ϕ(d)

在这里,记F(x)=∑d∣tμ(td)ϕ(d)F(x) = \sum_{d|t}\mu(\frac{t}{d})\phi(d)F(x)=dtμ(dt)ϕ(d)

F(x)F(x)F(x)是积性函数的狄利克雷卷积,因此F(x)F(x)F(x)也是积性函数,可以用线性筛法求得.

线性筛所能用到的信息:

F(p)=p−2F(p) = p-2F(p)=p2

F(px)=F(px−1)∗pF(p^x) = F(p^{x-1})*pF(px)=F(px1)p

F(p2)=p2−2∗p+1F(p^2) = p^2-2*p+1F(p2)=p22p+1

有关G(n)G(n)G(n)的计算:

n=∏piain = \prod{p_i^{a_i}}n=piai

则定义

g2(n)=∏pi⌈ai2⌉g_2(n) = \prod{p_i^{\lceil \frac{a_i}{2} \rceil}}g2(n)=pi2ai

g3(n)=∏pi⌈ai3⌉g_3(n) = \prod{p_i^{\lceil \frac{a_i}{3} \rceil}}g3(n)=pi3ai

那么G(n)=[An][Bg2(n)][Cg3(n)]G(n) = [\frac{A}{n}][\frac{B}{g_2(n)}][\frac{C}{g_3(n)}]G(n)=[nA][g2(n)B][g3(n)C]

这样的话式子=∑t=1G(t)F(t)= \sum_{t=1}G(t)F(t)=t=1G(t)F(t)中的G(t)G(t)G(t)F(t)F(t)F(t)均可在O(n)O(n)O(n)线性时间复杂度内预处理出来.

另外:这道题卡常数,真的恶心.

代码

#include <bits/stdc++.h>using namespace std;typedef long long ll;
const ll MOD = 1<<30;
const int maxn = 10000000;
int zhi[maxn+10],prime[maxn+10],pcnt,F[maxn+10];
int low[maxn+10],lowm[maxn+10],g2[maxn+10],g3[maxn+10];
void sieve(){zhi[1] = 1;low[1] = F[1] = g3[1] = g2[1] = 1;lowm[1] = 0;for(int i = 2;i <= maxn;++i){if(!zhi[i]) {F[i] = i-2,prime[pcnt++] = i;low[i] = i;lowm[i] = 1;g3[i] = g2[i] = i;}for(int j = 0;j < pcnt && prime[j]*i <= maxn;++j){zhi[i*prime[j]] = 1;if(i % prime[j] == 0){low[i*prime[j]] = low[i] * prime[j];lowm[i*prime[j]] = lowm[i]+1;if(i == low[i]){if(i == prime[j]) F[i*prime[j]] = prime[j]*prime[j]-2*prime[j]+1;else F[i*prime[j]] = F[i] * prime[j];}else{F[i*prime[j]] = F[i/low[i]]*F[low[i]*prime[j]];}g2[i*prime[j]] = g2[i];g3[i*prime[j]] = g3[i];if(lowm[i*prime[j]] % 2 == 1) g2[i*prime[j]] *= prime[j];if(lowm[i*prime[j]] % 3 == 1) g3[i*prime[j]] *= prime[j];break;}else{F[i*prime[j]] = F[i] * F[prime[j]];low[i*prime[j]] = prime[j];lowm[i*prime[j]] = 1;g2[i*prime[j]] = g2[i] * prime[j];g3[i*prime[j]] = g3[i] * prime[j];}}}
}int T ,A,B,C;
int main(){sieve();cin>>T;while(T--){scanf("%d%d%d",&A,&B,&C);ll ans = 0;for(int n = 1;n <= max(A,max(B,C));++n){ans = (ans + (A/n)*(B/g2[n])%MOD*(C/g3[n])%MOD*F[n]%MOD) % MOD;}cout<<ans<<endl;}return 0;
}

BZOJ4559 [成绩比较]

知识清单

  1. 动态规划
  2. 拉格朗日插值

题解

分两部分来解决:

1.先不考虑具体分数,只考虑满足相对排名计算得到方案数.

定义dp[i][j]dp[i][j]dp[i][j]表示仅考虑前iii节课,B神恰好碾压jjj个人.
转移方法:
显然dp[i][j]dp[i][j]dp[i][j]dp[i][j+k]dp[i][j+k]dp[i][j+k]转移过来.
具体转移方法:
考虑第iii门课,从j+kj+kj+k中选出kkk个,他们的分数大于B神,剩下jjj个放在B神的下面,表示继续被碾压.方案总数Ck+jkC_{k+j}^{k}Ck+jk.
剩下的还有N−1−(j+k)N-1-(j+k)N1(j+k)名同学,这些同学中取出Rank[i]−kRank[i]-kRank[i]k名同学放在B神上面,填满Rank[i]Rank[i]Rank[i].方案总数CN−1−j−kRank[i]−kC_{N-1-j-k}^{Rank[i]-k}CN1jkRank[i]k.
因此转移方程:
dp[i][j]=∑k=0k+j≤N−1dp[i][j+k]Ck+jkCN−1−j−kRank[i]−kdp[i][j] = \sum_{k=0}^{k+j≤N-1}{dp[i][j+k]C_{k+j}^{k}}C_{N-1-j-k}^{Rank[i]-k}dp[i][j]=k=0k+jN1dp[i][j+k]Ck+jkCN1jkRank[i]k
dp初始化:
dp[0][N−1]=1dp[0][N-1] = 1dp[0][N1]=1

该部分具体实现代码:

// dp[i][j]表示仅考虑前i门课程,其中有j名同学被B神碾压,的相对排名的方案数.  
dp[0][N-1] = 1;
for(int i = 1;i <= M;++i){for(int j = N-1;j >= 0;--j){for(int k = 0;k+j<=N-1;++k){ll res = C[j+k][k] * C[N-1-(j+k)][R[i]-1-k] % MOD;res = res * dp[i-1][j+k] % MOD;dp[i][j] = (dp[i][j] + res) % MOD;}}
}

2.求出满足题目给出的排名条件的分数具体分配方案数.

对于第iii门课,设B神的排名为Rank[i]Rank[i]Rank[i],则该门课产生的方案数就是枚举该门课B神的分数得到的方案数之和:
LRank[i][Ux]=∑t=1UxtN−Rank[i](Ux−t)Rank[i]−1L_{Rank[i]}[U_x] = \sum_{t=1}^{Ux}{t^{N-Rank[i]}(U_x-t)^{Rank[i]-1}}LRank[i][Ux]=t=1UxtNRank[i](Uxt)Rank[i]1
这个式子是关于UxU_xUxNNN次多项式,而UxUxUx最大则可能达到1e91e91e9,显然不可能直接来求,我们考虑拉格朗日插值.


LagrangeLagrangeLagrange插值简介

对于一个nnn次的多项式,只需要n+1n+1n+1个点即可唯一确定,而用n+1n+1n+1个点恢复这个nnn次多项式的方法就是LagrangeLagrangeLagrange插值法.

(xi,yi)(x_i,y_i)(xi,yi)为我们已经获得的N+1N+1N+1个点.

定义fi[x]=∏i!=jx−xjxi−xjf_i[x] = \prod_{i!=j}{\frac{x-x_j}{x_i-x_j}}fi[x]=i!=jxixjxxj

那么L[x]=∑i=1N+1yifi[x]L[x] = \sum_{i=1}^{N+1}{y_if_i[x]}L[x]=i=1N+1yifi[x]


如果这道题用LagrangeLagrangeLagrange插值求得了L[x]L[x]L[x],那么第iii门课的答案即是LRank[i][Ux]L_{Rank[i]}[U_x]LRank[i][Ux].

//拉格朗日实现具体代码
ll Lagrange(int id){//拉格朗日插值for(int xi = 1;xi <= N+1;++xi){x[xi] = xi;y[xi] = 0;for(int i = 1;i <= xi;++i){y[xi] = (y[xi] + (mod_pow(i,N-R[id])*mod_pow(xi-i,R[id]-1)%MOD)) % MOD;}}ll ans = 0;for(int xi = 1;xi <= N+1;++xi){ll res = y[xi];for(int xj = 1;xj <= N+1;++xj){if(xj == xi) continue;res = res * (U[id] - xj + MOD) % MOD;res = res * div(xi - xj + MOD) % MOD;}ans = (ans + res) % MOD;}return ans;
}

综合起来,这道题的答案就是ans=dp[M][K]∗∏i=1MLRank[i][Ux]ans = dp[M][K]*\prod_{i=1}^{M}{L_{Rank[i]}[U_x]}ans=dp[M][K]i=1MLRank[i][Ux]

###实现代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>using namespace std;#define pr(x) cout<<#x<<":"<<x<<endl
typedef long long ll;
int N,M,K;
const ll MOD = 1e9+7;
ll mod_pow(ll x,ll n){if(n == 0) return 1;ll res = 1;while(n){if(n&1) res = res * x %MOD;x = x * x % MOD;n >>= 1;}return res;
}
const int maxn = 107;
ll R[maxn],U[maxn],dp[maxn][maxn];
ll C[maxn][maxn];
ll div(ll x){return mod_pow(x,MOD-2);
}
void initC(){C[0][0] = 1;for(int i = 1;i < maxn;++i){C[i][0] = 1;for(int j = 1;j <= i;++j){C[i][j] = (C[i-1][j] + C[i-1][j-1])%MOD;}}
}
ll x[maxn],y[maxn];
ll Lagrange(int id){//拉格朗日插值for(int xi = 1;xi <= N+1;++xi){x[xi] = xi;y[xi] = 0;for(int i = 1;i <= xi;++i){y[xi] = (y[xi] + (mod_pow(i,N-R[id])*mod_pow(xi-i,R[id]-1)%MOD)) % MOD;}}ll ans = 0;for(int xi = 1;xi <= N+1;++xi){ll res = y[xi];for(int xj = 1;xj <= N+1;++xj){if(xj == xi) continue;res = res * (U[id] - xj + MOD) % MOD;res = res * div(xi - xj + MOD) % MOD;}ans = (ans + res) % MOD;}return ans;
}
int main(){initC();ios::sync_with_stdio(false);cin>>N>>M>>K;for(int i = 1;i <= M;++i) cin>>U[i];for(int i = 1;i <= M;++i) cin>>R[i];// dp[i][j]表示仅考虑前i门课程,其中有j名同学被B神碾压,的相对排名的方案数.dp[0][N-1] = 1;for(int i = 1;i <= M;++i){for(int j = N-1;j >= 0;--j){for(int k = 0;k+j<=N-1;++k){ll res = C[j+k][k] * C[N-1-(j+k)][R[i]-1-k] % MOD;res = res * dp[i-1][j+k] % MOD;dp[i][j] = (dp[i][j] + res) % MOD;}}}ll ans = dp[M][K];for(int i = 1;i <= M;++i){ans = ans * Lagrange(i) % MOD;}cout<<ans<<endl;return 0;
}

BZOJ2633 [已经没有什么好害怕的了]

知识清单

  1. 容斥原理
  2. 动态规划

题意

给出nnn个数 aia_iainnn个数bib_ibi,将aia_iaibib_ibi进行匹配,使得匹配中ai&gt;bia_i&gt;b_iai>bi的对数比ai&lt;bia_i&lt;b_iai<bi的匹配数大kkk组.

题解

首先将a,ba,ba,b数组排序,然后对于每个iii求出满足bj&lt;ai(1≤j≤n)b_j &lt; a_i (1≤j≤n)bj<ai(1jn)jjj的个数,并记为cnt[i]cnt[i]cnt[i].

定义f[i][j]f[i][j]f[i][j]表示仅考虑前iiiaaa中,满足有jjj对匹配使得au&gt;bva_u &gt; b_vau>bv成立的方案数.(显然1≤j≤i1≤j≤i1ji) (注意这个定义中不要求剩下的aaabbb进行匹配.)

那么我们可以得到转移方程:
f[i][j]=f[i−1][j]+f[i−1][j−1]∗(cnt[i]−(j−1))f[i][j] = f[i-1][j] + f[i-1][j-1]*(cnt[i]-(j-1))f[i][j]=f[i1][j]+f[i1][j1](cnt[i](j1))

看起来似乎f[n][j]∗(n−j)!f[n][j]*(n-j)!f[n][j](nj)!就是我们要找的答案?

但显然并不是,因为(n−j)!(n-j)!(nj)!表示的剩下未匹配的元素进行随机搭配的时候,有时候也会搭配出满足au&gt;bva_u &gt; b_vau>bv的匹配,像这种就是不合法的,因此我们还要进行去重操作.

g[i]g[i]g[i]表示在nnn个匹配中,恰好有iii个匹配满足au&gt;bva_u &gt; b_vau>bv的方案数.显然这回g[(n+k)/2]g[(n+k)/2]g[(n+k)/2]就是我们要的答案.

容易想到转移方程:
g[i]=f[n][i]∗(n−i)!−g[i+1]∗Ci+1i−g[i+2]∗CI+2i−...−g[n]∗Cnig[i]=f[n][i]*(n-i)!-g[i+1]*C^{i}_{i+1}-g[i+2]*C^{i}_{I+2}-...-g[n]*C^{i}_{n}g[i]=f[n][i](ni)!g[i+1]Ci+1ig[i+2]CI+2i...g[n]Cni

解释一下为什么要乘以CjiC^{i}_{j}Cji这个系数:因为f[n][i]∗(n−i)!f[n][i]*(n-i)!f[n][i](ni)!产生的满足有jjjau&gt;bva_u &gt; b_vau>bv的匹配数的方案数可以由固定iii个匹配数来得到(剩下的j−ij-iji个匹配由(j−i)!(j-i)!(ji)!部分负责).而固定iii个匹配数的方案数刚好就是CjiC^{i}_{j}Cji

得到这个式子倒着转移就可以了.

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>using namespace std;
const ll MOD = 1e9+9;
int n,k;
const int maxn = 2007;
ll f[maxn][maxn],g[maxn];
ll a[maxn],b[maxn];
ll fac[maxn];
ll C[maxn][maxn];
ll cnt[maxn];
int main(){C[0][0] = fac[0] = 1;for(int i = 1;i <= 2000;++i) {fac[i] = fac[i-1] * i % MOD;C[i][0] = 1;}for(int i = 1;i <= 2000;++i) {for(int j = 1;j <= i;++j){C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD;}}cin>>n>>k;if((n+k)%2 != 0) return puts("0");for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);for(int i = 1;i <= n;++i) scanf("%lld",&b[i]);sort(a+1,a+1+n);sort(b+1,b+1+n);for(int i = 1;i <= n;++i){cnt[i] = lower_bound(b+1,b+1+n,a[i])-b-1;}f[0][0] = 1;for(int i = 1;i <= n;++i){f[i][0] = 1;for(int j = 1;j <= i;++j){f[i][j] = f[i-1][j] + (f[i-1][j-1]*max(cnt[i]-j+1,0LL)%MOD);f[i][j] %= MOD;}}for(int i = n;i >= (n+k)/2;--i){g[i] = f[n][i]*fac[n-i]%MOD;for(int j = i+1;j <= n;++j){g[i] = (g[i] + MOD - (C[j][i] * g[j] % MOD)) % MOD;}}cout<<g[(n+k)/2]<<endl;return 0;
}

BZOJ3930 [选数]

知识清单

  1. 容斥原理 (或莫比乌斯反演)

题解

题目给的一个很关键的信息就是H−L≤1e5H-L ≤ 1e5HL1e5.这意味着如果在区间[L,H][L,H][L,H]中选出NNN个不完全相同的整数,那么他们的GCD≤H−L≤1e5GCD≤H-L≤1e5GCDHL1e5
证明:GCD(x,y)=GCD(x−y,y)&lt;=x−yGCD(x,y) = GCD(x-y,y) &lt;= x-yGCD(x,y)=GCD(xy,y)<=xy

如果将[L,H][L,H][L,H]中的各个元素除以KKK,就相当于在(L−1K,HK](\frac{L-1}{K},\frac{H}{K}](KL1,KH]中找NNN个不完全相同的数使得其GCD=1GCD = 1GCD=1

F[x]F[x]F[x]表示满足在(L−1K,HK](\frac{L-1}{K},\frac{H}{K}](KL1,KH]中找NNN个不完全相同的元素,使得其GCD=1GCD=1GCD=1的方案数.

显然F[x]=([HKx]−[L−1Kx])N−([HKx]−[L−1Kx])−F[2∗x]−F[3∗x]−....F[x] = ([\frac{H}{Kx}]-[\frac{L-1}{Kx}])^N - ([\frac{H}{Kx}]-[\frac{L-1}{Kx}]) - F[2*x] - F[3*x] -....F[x]=([KxH][KxL1])N([KxH][KxL1])F[2x]F[3x]....

遇见这种递推式子直接倒着进行转移就可以了.
注意,如果 KKK 存在于区间[L,H][L,H][L,H]之间,那么ans++ans++ans++,因为这种属于NNN个数字全部相等的情况,我们的算法是没有考虑进去的.

另外,
这题实际上可以使用莫比乌斯反演,而且莫比乌斯反演形式特别直接,但是复杂度不对.

重新定义F[x]F[x]F[x]为在[L,H][L,H][L,H]中找NNN个数使得其GCD=XGCD=XGCD=X的方案数
我们可以得到
∑n∣dF[d]=([Hn]−[L−1n])N\sum_{n|d}{F[d]} = ([\frac{H}{n}]-[\frac{L-1}{n}])^NndF[d]=([nH][nL1])N
反演得到,
F[n]=∑n∣dμ(dn)([Hd]−[L−1d])NF[n] = \sum_{n|d}{\mu(\frac{d}{n})([\frac{H}{d}]-[\frac{L-1}{d}])^N}F[n]=ndμ(nd)([dH][dL1])N

我看到其他的博客有讲到分块的方法,但感觉复杂度有点玄学.

const ll MOD = 1e9+7;
ll N,K,L,R;
ll mod_pow(ll x,ll n){ll res = 1;while(n){if(n & 1) res = res * x % MOD;x = x * x % MOD;n >>= 1;}return res;
}
ll F[200007];
const int maxn = 200000;
int main(){cin>>N>>K>>L>>R;ll ans = K >= L && K <= R;R /= K;L --;L /= K;ll len = R - L;for(ll d = len;d >= 1;--d){ll res = R/d - L/d;F[d] = (mod_pow(res,N)-res+MOD) % MOD;for(ll k = 2*d;k <= len;k += d)F[d] = (F[d] - F[k] + MOD) % MOD;}cout<<ans+F[1]<<endl;return 0;
}

徐州网络赛 Easy Math

前置技能

  1. 容斥原理
  2. 线性筛
  3. 杜教筛

题解

∑i=1mμ(in)\sum_{i=1}^{m}\mu(in)i=1mμ(in)

nnn存在平方因子的时候,直接输出000作为答案,这是很显然的.

否则,n=p1p2...pkn = p_1p_2...p_kn=p1p2...pk,不含平方因子.

考虑区间[1,m][1,m][1,m]中的数字iii,如果iii不含有因子p1p_1p1,则可以使用积性函数的性质.

即:μ(i∗n)=μ(i∗np1∗p1)=−μ(i∗np1)\mu(i*n) = \mu(i*\frac{n}{p_1}*p_1) = -\mu(i*\frac{n}{p_1})μ(in)=μ(ip1np1)=μ(ip1n)

而区间[1,m][1,m][1,m]中的数并不全都与p1p_1p1互质,这就会造成μ(i∗n)=0\mu(i*n) = 0μ(in)=0μ(i∗np1)≠0\mu(i*\frac{n}{p_1}) \ne 0μ(ip1n)̸=0的情况,这就要求我们用容斥的思想来去掉这部分.

如果iii中恰好有一个因子p1p_1p1,则μ(i∗np1)=μ(ip1∗n)\mu(i*\frac{n}{p_1}) = \mu(\frac{i}{p_1}*n)μ(ip1n)=μ(p1in)

因此要减去∑i=1⌊np1⌋μ(in)\sum_{i=1}^{\lfloor \frac{n}{p_1} \rfloor} \mu(in)i=1p1nμ(in)

而如果iii中有多于111个的pip_ipi因子,那么这部分的莫比乌斯函数值无论是在那部分中都是000,因此不会对最终答案造成影响.

这样相当于降低了问题的规模.

我们可以列出递推式子,然后递推解决这个问题.

∑i=1nμ(in)=−∑i=1nμ(i∗np1)+∑i=1⌊np1⌋μ(in)\sum_{i=1}^{n}{\mu(in)} = -\sum_{i=1}^{n}{\mu(i*\frac{n}{p_1})} + \sum_{i=1}^{\lfloor \frac{n}{p_1} \rfloor} \mu(in)i=1nμ(in)=i=1nμ(ip1n)+i=1p1nμ(in)

递推终止的条件是

  1. n==1n == 1n==1 时候,使用杜教筛得到莫比乌斯函数的前缀和
  2. ∑\sum的上限为000时候,直接返回000.
typedef long long ll;
const int N = 10000000;;
int mu[N+10],prime[N+10],pcnt,zhi[N+10];
void sieve(){pcnt = 0;mu[1] = zhi[1] = 1;for(int i = 2;i <= N;++i){if(!zhi[i]) mu[i] = -1,prime[pcnt++] = i;for(int j = 0;j < pcnt && prime[j]*i <= N;++j){zhi[i*prime[j]] = 1;if(i % prime[j] == 0){mu[i*prime[j]] = 0;break;}else{mu[i*prime[j]] = -mu[i];}}}for(int i = 1;i <= N;++i) mu[i] += mu[i-1];
}
map<ll,int> rec,vis;
int Mu(int x){if(x <= N) return mu[x];if(vis[x]) return rec[x];int res = 1,now = x,nxt;while(now >= 2){nxt = x/(x/now+1);res -= (now - nxt) * Mu(x/now);now = nxt;}vis[x] = 1;return rec[x] = res;
}
ll m,n;
ll np[20];int npcnt;
int Ans(ll u,ll d){if(d == 1) return Mu(u);if(u == 0) return 0;for(int i = 0;i < npcnt;++i){if(d % np[i] == 0){return -Ans(u,d/np[i]) + Ans(u/np[i],d);}}
}
bool divide(){ll x = n;for(ll i = 2;i * i <= n;++i){int cc = 0;if(x % i == 0) np[npcnt++] = i;while(x % i == 0) x /= i,cc++;if(cc >= 2) return false;}if(x > 1) np[npcnt++] = x;return true;
}
int main(){sieve();cin>>m>>n;if(!divide()) return puts("0");cout<<Ans(m,n)<<endl;return 0;
}

NWERC2015 Debugging

题目描述

有一份包含一个Bug的n,(1≤n≤106)n,(1 \le n \le 10^6 )n,(1n106)行代码,运行一次到崩溃的时间为r,1≤r≤109r,1 \le r \le 10^9r,1r109.
现在你可以在任意一行花费时间p,1≤p≤109p,1\le p \le 10^9p,1p109设置一个printfprintfprintf语句来判断程序是否运行到这里.
请问在最坏情况下,最少需要多少时间可以定位到bug所在行.

题解

因为我们调试的时候往往会运行很多次程序,而每次运行完之后,我们都能定位bug在哪一块代码行中.

因此我们动态规划的思想得到递推公式.
dp[n]dp[n]dp[n]表示调试nnn行代码所需要花的时间.

dp[n]=min1≤k≤n(dp[nk+1]+k∗p+r)dp[n] = min_{1 \le k \le n}(dp[\frac{n}{k+1}]+k*p + r)dp[n]=min1kn(dp[k+1n]+kp+r)

直接递推的时间复杂度是O(n2)O(n^2)O(n2)的,而如果我们发现对于[nk+1][\frac{n}{k+1}][k+1n]相等的kkk,我们只取kkk的最小值就可以了.

所以通过底数分块,我们可以求得转移的时间复杂度为n\sqrt{n}n,而真正有效的状态数也只有n\sqrt{n}n,所以时间复杂度上限不会超过O(n)O(n)O(n).

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321121.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于Visual Studio 2019的前期详情

近日&#xff0c;来自微软公司的 John Montgomery 正式宣布&#xff0c;Visual Studio 2019已进入开发阶段。Montgomery 表示&#xff0c;之所以选择在这个时间点公开这个消息&#xff0c;是因为微软准备在 GitHub 上公开可见的项目&#xff08;包括 .NET 和 Roslyn&#xff09…

nssl1522-简单数数题【dp】

正题 题目大意 nnn个数的一个集合&#xff0c;求一个有多少个子集使得这个子集的所有子集的权值和的和是mmm的倍数 解题思路 考虑dp&#xff0c;选中集合中每一个数的贡献次数是2∣S∣−12^{|S|-1}2∣S∣−1&#xff0c;设fi,j,kf_{i,j,k}fi,j,k​表示选到第iii&#xff0c;现…

蛋糕店

蛋糕店 题目大意&#xff1a; 有n个人&#xff0c;让他们排队&#xff0c;每个人都有一个愤怒值&#xff0c;总值为每个人的愤怒值乘上&#xff08;他在队列中的位置-1&#xff09;加在一起 原题&#xff1a; 题目描述 最近小G新开了一家蛋糕店。开业第一天&#xff0c;一…

开源的,跨平台的.NET机器学习框架ML.NET

微软在Build 2018大会上推出的一款面向.NET开发人员的开源&#xff0c;跨平台机器学习框架ML.NET。 ML.NET将允许.NET开发人员开发他们自己的模型&#xff0c;并将自定义ML集成到他们的应用程序中&#xff0c;而无需事先掌握开发或调整机器学习模型的专业知识。在采用通用机器学…

nssl1519-背包签到题【数论】

正题 题目链接:http://10.156.31.134/contestnew.aspx?cid189 题目大意 nnn种物品&#xff0c;每种aia_iai​个。放进kkk个有序盒子求方案数&#xff08;可以不放完&#xff09; 解题思路 不放完其实就是k1k1k1个盒子&#xff0c;插板法求CkaiaiC_{ka_i}^{a_i}Ckai​ai​​&…

【dfs】相似度

相似度 题目大意&#xff1a; 有两个图&#xff0c;问他们的相似度是多少&#xff08;相似度为连接两个点的相样线的条数&#xff09; 原题&#xff1a; 题目描述 小G通过摆放一些城市和道路构成了一个世界地图。趁着小G出去玩的时候&#xff0c;大G把小G的世界地图上的城…

虚树-树上动态规划的利器

虚树 问题引入 在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值. 如果我们直接在整颗树上进行dpdp的话,时间复杂度与询问的次数有关,这显然是不可接受的,如果我们可以找到一种动态规划的方法,使其时间复杂度与询问中点的实际…

牛客练习赛69D-火柴排队【dp】

正题 题目链接:https://ac.nowcoder.com/acm/contest/7329/D 题目大意 nnn个数的序列&#xff0c;排序后让随机kkk个数加上ddd&#xff0c;求依旧满足单调上升的期望概率 解题思路 对于一个位置加上ddd后会让到后面一段范围内都得加上ddd。我们预处理一个lil_ili​表示如果ii…

微软推出Visual Studio Kubernetes工具包预览版

微软表示&#xff0c;利用 Visual Studio Kubernetes 这个工具&#xff0c;使用者可以直接在该环境中&#xff0c;构建 Kubernetes 容器应用程序项目&#xff0c;或者让现有的 .NET 网页应用程序也兼容 Kubernetes。除了公有云基础架构环境要支持 Kubernetes&#xff0c;微软现…

伸展树模板

伸展树模板 #include <iostream> #include <cstdio>#define pr(x) std::cout << #x << " : " << x << std::endlclass SplayTree{ public:struct Node{int val;int size;int tag;Node *father;Node *son[2];Node(int val,Node *…

【DP】Sam数

Sam数 题目大意&#xff1a; 问位数为n&#xff0c;且每一位的数字与相邻数字的差值小于等于2的数有多少个 原题&#xff1a; 题目描述 小G最近发现了一种非常有趣的数&#xff0c;他将这种数称之为Sam数。Sam数具有以下特征&#xff1a;相邻两位的数字之差不超过2。小G还…

基于docker 如何部署surging分布式微服务引擎

1、前言转眼间surging 开源已经有1年了&#xff0c;经过1年的打磨&#xff0c;surging已从最初在window 部署的分布式微服务框架&#xff0c;到现在的可以在docker部署利用rancher 进行服务编排的分布式微服务引擎&#xff0c;再把业务进行剥离&#xff0c; 通过配置路径就能驱…

P4213-[模板]杜教筛(Sum)

正题 题目链接:https://www.luogu.com.cn/problem/P4213 题目大意 给出nnn&#xff0c;求∑i1nφ(i)\sum_{i1}^n\varphi(i)i1∑n​φ(i) 和 ∑i1nμ(i)\sum_{i1}^n\mu(i)i1∑n​μ(i) 解题思路 考虑如何将φ\varphiφ卷起来&#xff0c;我们可以乘上一个函数I(I(x)1)I(I(x)1…

线段树专题-等差子序列 BZOJ-2124

线段树专题-等差子序列 感谢 感谢孙耀峰的线段树PPT,使我获益匪浅. 题目来源 BZOJ−2124BZOJ-2124BZOJ−2124 题意 给出长度为nnn的1−n1-n1−n的排列AAA 问是否存在一组1≤p1≤p2≤...≤pl≤n,l≥31 \le p_1 \le p_2 \le ... \le p_l \le n,l \ge 31≤p1​≤p2​≤...≤p…

【模拟】小游戏

小游戏 题目大意&#xff1a; 有n个数形成一个环&#xff0c;从第S个开始&#xff0c;先往后数N个数然后把这个数取出来&#xff0c;再往前数K个数把这个数取出来&#xff0c;问取的数字依次是什么 原题&#xff1a; 题目描述 【题目背景】 yk同学是一个灰常灰常有爱的同…

P4051-[JSOI2007]字符加密【SA】

正题 题目链接:https://www.luogu.com.cn/problem/P4051 题目大意 给一个字符串&#xff0c;求它当每个环状字符串&#xff08;比如ABCABCABC的就是ABC,CAB,BCAABC,CAB,BCAABC,CAB,BCA&#xff09;排序后所有串的末尾连起来当字符串。 解题思路 这个其实就是每个串的后缀加上…

DevOps 实践:千里之行

在上一篇 DevOps 渊源&#xff1a;角色消融 中我们分析了在作坊式团队中的责任重叠&#xff0c;也回顾了 DBA 角色的消融。那么&#xff0c;如今我们讲的 DevOps 又是什么角色的消融呢&#xff1f; 我想你已经猜到了&#xff0c;接下来要消融的角色就是运维人员了。那这次又是什…

线段树专题-黑白棋盘 BZOJ-1453

线段树专题-黑白棋盘 题目来源 BZOJ−1453BZOJ-1453BZOJ−1453 题意 QQQ次操作每次操作给出(x,y)(x,y)(x,y),将(x,y)(x,y)(x,y)个格子颜色取反每次操作后,输出棋盘上黑白联通块的个数n≤100,Q≤104n \le 100,Q \le 10^4n≤100,Q≤104 题解 显然不能直接套并查集,因为直接套…

约数个数

约数个数 题目大意&#xff1a; 求a到b之间每个数的约数的个数之和 原题&#xff1a; 题目描述 定义f(x)为x的约数个数&#xff0c;x为正整数。 f(a)f(a1)……f(b)&#xff0c;即a,b之间每个数的约数的总和。 输入 一行两个正整数a、b&#xff0c;以一个空格隔开。 输出…

P2257-YY的GCD【莫比乌斯反演】

正题 题目链接:https://www.luogu.com.cn/problem/P2257 题目大意 给出n,mn,mn,m&#xff0c;求∑i1n∑j1m[gcd(i,j)∈p]\sum_{i1}^n\sum_{j1}^m[gcd(i,j)\in p]i1∑n​j1∑m​[gcd(i,j)∈p] 定义ppp是质数集 解题思路 首先考虑定义f(x)∑i1n∑j1m[gcd(i,j)x]f(x)\sum_{i1}…