Day6

发布时间 2023-07-29 20:44:32作者: Qinzh

Day6

T1

没啥玩意好说的,就是别忘删freopen

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define gt getchar
using namespace std;
inline ll read(){
    ll x=0,f=1;char ch=gt();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gt();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gt();}
    return x*f;}
ll a[200005], bj[20000005];
int main()
{
	//freopen("a4.in", "r", stdin); 
    ll ans = 0;
    int n = read(), m = read();
    for(int i = 1;  i<= m; ++ i)a[i] = read();
    //sort(a + 1, a + n + 1);
    for(int i = 1; i <= m; ++ i)
    {
        for(ll j = 1; j * a[i] <= n; ++ j)
        {
            if(bj[j * a[i]] == 0)bj[j * a[i]] = 1, ++ ans;
            //if(j % a[i] == 0)break;
        }
    }
    cout << ans;
    return 0;
}

T2

我的做法是先欧拉筛一遍找出所有质数,然后埃氏筛一遍找出每个点的 \(fa\)。不过正解是一遍欧拉即可,差别不大,也不难。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define gt getchar
#define pt putchar
using namespace std;
inline ll read(){
	ll x=0,f=1;char ch=gt();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=gt();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gt();}
	return x*f;}
inline void print(ll x){if(x<0)pt('-'),x=-x;if(x>9)print(x/10);pt(x%10+48);pt('\n');}
int n, q;
int Prime[10000007], fa[10000007], No_Prime[10000007];
int ans[100005];
ll solve(int x, int y)
{
        int cnt1 = 0, cnt2 = 0;
        while(x != 1)
        {
            ans[++ cnt1] = x; x /= fa[x];
        }
        reverse(ans + 1, ans + cnt1 + 1);
        while(y != 1)
        {
            int t = lower_bound(ans + 1, ans + cnt1 + 1, y) - ans;
            if(ans[t] == y && t <= cnt1){
                return cnt1 - t + cnt2;
            }
            ++ cnt2;
            y /= fa[y];
        }
        return cnt1 + cnt2;
}
int main()
{
    int cnt = 0;
	n = read(), q = read();
    fa[1] = 0;
	for(int i = 2; i <= n; ++ i)
    {
        if(!No_Prime[i])Prime[++ cnt] = i;
        for(int j = 1; j <= cnt; ++ j)
        {
            ll x = Prime[j] * i;
            if(x > n)
                break;
            No_Prime[x] = 1;
            if(i % Prime[j] == 0) break;
        }
    }
	for(int i = cnt; i >= 1 ; -- i)
    {
		for(int j = 1; j <= n; ++ j)
        {
			if(1ll * Prime[i] * j > n)break;
			if(fa[Prime[i] * j] == 0)fa[Prime[i] * j] = Prime[i];
		}
	}
	while(q--)
	{
		int x = read(), y = read();
		if(x > y)swap(x, y);
		cout << solve(x, y) << '\n';
	}
	return 0;
}

T3

易得 \(x+y\)\(x-y\) 奇偶性相同,那我们枚举 \(x-y\),如果它是偶数,然后那么合法的 \(x+y\) 的个数就是 \(\frac{2n-a}{a}-1\)(下取整),如果是奇数,那么再减去 \(\frac{n-a}{2a}\)(下取整)。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define gt getchar
using namespace std;
inline ll read(){
    ll x=0,f=1;char ch=gt();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gt();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gt();}
    return x*f;}
int n, res;
int main()
{
    n = read();
    for(int i = 1; i < n; ++ i)
    {
        res += (2 * n - i) / i - 1;
        if(i & 1) res -= (2 * n - i) / (2 * i);
    }
    cout << res << '\n';
    return 0;
}


T4

找出 \(i\) 的所有约数,设其个数为 \(d(i)\) ,其在长度为 \(k\) 的序列中有 \(d(i) ^ k\)

但其中有一些序列的最小公倍数会小于 \(j\) 设这些最小公倍数为 \(j\)\(j\) 一定是 \(i\) 的约数

所以继续减去 \(\sum_{j|i, j <i}d(j)^k\)

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define gt getchar
using namespace std;
inline ll read(){
    ll x=0,f=1;char ch=gt();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gt();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gt();}
    return x*f;}
int n, k, f[1000005];
const int mod = 998244353;
ll ksm(int x, int k)
{
	if(k == 1)return x;
	ll t = ksm(x, k / 2);
    if(k & 1)return ((t * t) % mod * x) % mod;
    return (t * t) % mod;
}
int main()
{
	n = read(), k = read();
	for(int i = 1; i <= n; ++ i)
    {
        for(int j = i; j <= n; j += i)
        {
            ++ f[j];
        }
        f[i] = ksm(f[i], k);
    }
	for(int i = 1; i <= n; ++ i)
    {
        for(int j = 2 * i; j <= n; j += i)
        {
            f[j] = (f[j] - f[i] + mod) % mod;
        }
    }
	for(int i = 1; i <= n; ++ i)cout << f[i] << ' ';
    return 0;
}


exgcd

方程 \(xa + yb = g \rightarrow (\gcd(a, b) = g)\)

\(\gcd(b, a \bmod b) = g \rightarrow x'b + y'(a \bmod b) = g\)

\(x'b + y'a - y'b \lfloor\frac{a}{b}\rfloor = g\)

\(y'a + (x' - y' \lfloor\frac{a}{b}\rfloor) \cdot b = g\)


int exgcd(int a, int b, int &x, int &y){
	//求g = gcd(a, b)以及 xa + yb = g
    if(!b){x = 1, y = 0; return 0;}
    int xp, yp;
    int g = exgcd(b, a % b, xp, yp);
    //xp * b + yp * (a % b) = g
    //xp * b + yp * (a - b * (a / b)) = g
    //xp * b + yp * a - yp * b * (a / b) = g
    //yp * a + (xp - yp *(a/b)) * b = g
  	x = yp;y = xp - yp * (a / b);
    return g;
}

中国剩余定理

LuoguP1495

LuoguP4777

法二(ExGcd):

\(x \bmod p_1 = a_1, x \bmod p_2 = a_2, x \bmod p = a\)

\(x = k_1 \times p_1 + a_1 = k_2 \times p_2 + a_2\)

\(\therefore k_1 \times p_1 - k_2 \times p_2 = a_2 - a_1\)

void solve(int p1, int a1, int p2, int a2, int &p, int &a){
    int g, k1, k2;
    g = exgcd(p1, p2, k1, k2);
    k2 = -k2;
    if((a2 - a1) % g != 0)p = -1, a = -1;
    else{
    int k = (a2 - a1) / g;
        k1 = k1 * k, k2 = k2 * k;
        int x = k1 * p1 + a1;
        p = p1 / g * p2;
        a = (x % p + p) % p;
    }
}

费马小定理

\(a, p\) 互质且 \(p\) 为质数

\(a^{p-1}\equiv1(\bmod\) \(p)\)

Lucas定理

\(Lucas\) 定理:

先将 \(n, m\) 转换为 \(p\) 进制.

短除法转换进制

\(n = 25, m = 12, p = 3\) ,

\(n_{(3)} = 221, m_{(3)} = 110\)

\[\binom{25}{12} \bmod p = \binom{n_1}{m_1}\binom{n_2}{m_2}\binom{n_3}{m_3} \bmod p \]

int lucas(int n, int m, int p){
    while(n){
        ++x[0];
        x[x[0]] = n % p;
        n = n / p;
    }//n的p进制表示 
    while(m){
        ++y[0];
        y[y[0]] = m % p;
        m = m / p;
    }
    int ans = 1;
    for(int i = 1; i <= x[0]; ++i)
        ans = 1ll * ans * c[x[i]][y[i]] % p;
    return ans; 
}
int main(){
    cin >> n >> m >> p;
    for(int i = 0; i <= p; ++i){
    	c[i][0] = 1;
    	for(int j = 1; j <= i; ++j){
        	c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % p;
		}
	}
	return 0;
}

\(O(\log n)\)

LuoguP3807

卢卡斯定理只适用于 \(p\) 为质数, 当 \(p\) 不为质数时, 将其质因数分解

然后中国剩余定理合并, 计算可得

例3

\(x\) 拆为 \(k\) 个不同组合数之和

\(x \le 10 ^ 9, k \le 10^3\)

酱汁构造(

\[x = \overbrace{1 + 1 + 1 + ...+1}^{k - 1} +(n - k + 1) \]

\[= \binom{1}{0}+\binom{2}{0} + .... +\binom{k - 1}{0}+\binom{n - k + 1}{1} \]

数论函数

这玩意该怎么打 \(\LaTeX\) 啊啊啊

鸽了

组合数学

隔板法就是有 \(n\) 个球,用 \(m\) 个板子隔开的方案数,板子不能相邻,也不能在边上

实际就是,有 \(n - 1\) 个空,选 \(m\) 个板子插进去

\(C\binom{n - 1}{m}\)

现在有一个高 \(n\)\(m\) 的矩阵球从左上到右下的方案数

路径长为 \(n + m -1\)

其中有 \(n\) 步向下

就是从 \(n+m-1\) 步中选 \(n\) 步向下

\(C\binom{n + m - 1}{n}\)