简单数学刷题

P1414 又是毕业季II

把每个数的所有因数都枚举出来,假设因数为i,则让cnt[i]++。

根据选x+1个数的gcd小于等于选x个数的gcd

    for (int i = 1; i <= n; i++)//先枚举选几个人
    {
        while (mx > 0 && cnt[mx] < i)//然后从最大的因数往小的枚举可以选出的情况
            mx--;
        cout << mx << endl;
    }

一定能通过这样把所有i的情况找到:
如果极端情况所有数都是质数,由于cnt[1]==k,因此除了i=1会输出最大数以外,其他都会输出1.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 2e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int cnt[maxn];

int main()
{
    fastio;
    int n;
    cin >> n;
    int mx = 0;
    for (int t = 1; t <= n; t++)
    {
        int x;
        cin >> x;
        mx = max(x, mx);
        for (int i = 1; i * i <= x; i++)
        {
            if (x % i == 0)
            {
                cnt[i]++;
                if (i * i != x)
                    cnt[x / i]++;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        while (mx > 0 && cnt[mx] < i)
            mx--;
        cout << mx << endl;
    }
    return 0;

}

CF757B Bash's Big Day

同上,只不过要找cnt[i]不等于1的最大cnt[i]

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 1e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int cnt[maxn];

int main()
{
    fastio;
    int n;
    cin >> n;
    int mx = 0;
    while (n--)
    {
        int x;
        cin >> x;
        mx = max(x, mx);
        for (int i = 1; i * i <= x; i++)
        {
            if (x % i == 0)
            {
                cnt[i]++;
                if (x / i != i)
                    cnt[x / i]++;
            }
        }
    }
    int ans = 1;
    for (int i = 2; i <= mx; i++)
        ans = max(ans, cnt[i]);
    cout << ans << endl;
    return 0;

}

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

\(x0*y0=P*Q\)

直接暴力枚举即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 2e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    fastio;
    int a, b;
    cin >> a >> b;
    int c = a * b;
    int ans = 0;
    for (int i = 1; i * i <= c; i++)
    {
        if (c % i == 0)
        {
            int j = c / i;
            if (gcd(i, j) == a)
            {
                ans++;
                if (i * i != c)
                    ans++;
            }
        }
    }
    cout << ans;
    return 0;

}

P1072 [NOIP2009 提高组] Hankson 的趣味题

image

然后\(x|b_1\),枚举x即可,复杂度n*sqrt(b1)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 2e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    fastio;
    int t;
    cin >> t;
    while (t--)
    {
        ll a0, a1, b0, b1;
        cin >> a0 >> a1 >> b0 >> b1;
        if (b1 % b0 || a0 % a1) {
            cout << 0 << "\n";
            continue;
        }
        int ans = 0;
        for (ll x = 1; x * x <= b1; x++)
            if (b1 % x == 0)
            {
                if (x % a1 == 0 && gcd(x / a1, a0 / a1) == 1 && gcd(b1 / b0, b1 / x) == 1)
                    ans++;
                ll y = b1 / x;
                if (x == y|| y % a1)continue;
                if (gcd(y / a1, a0 / a1) == 1 && gcd(b1 / b0, b1 / y) == 1)
                    ans++;
            }
        cout << ans << "\n";
    }
    return 0;

}

CF687B Remainders Game

暴力做法,直接递推lcm取模:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 1e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

ll lcm(ll a, ll b)
{
    return a / gcd(a, b) * b;
}

int main()
{
    fastio;
    ll n, k;
    cin >> n >> k;
    ll l = 1;
    while (n--)
    {
        ll x;
        cin >> x;
        l = lcm(x, l) % k;
        if (!l)
            break;
    }
    if (l)
        cout << "No";
    else cout << "Yes";
    return 0;

}

某个复杂做法:
由于\(lcm \% k==0\),只需要去check所有与k有相同质因子的数x中的每一个质因子:

假设这个质因子是p,去看是否cntx[p]>=cntk[p](x中p的个数是否大于k中p的个数),如果可以就凑出了k中的一种质因子(一定要一次全部凑出来,因为lcm的每个素因子个数等于所有数这个素因子个数的max)

最后看看k是不是1就知道能不能凑出k

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 1e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : a;
}

int v[maxn], p[maxn], cnt;

//bool v[maxn];卡常请把v改成1降低常数

void init_e()
{
    memset(v, 0, sizeof(v));
    cnt = 0;
}

void Euler_sieve(int n)
{
    init_e();
    cnt = 0;
    for (int i = 2; i <= n; i++) {
        if (v[i] == 0) { v[i] = i; p[++cnt] = i; }
        for (int j = 1; j <= cnt; j++)
        {
            if (p[j] > v[i] || p[j] > n / i)break;
            v[i * p[j]] = p[j];
        }
    }
}



int main()
{
    int n, k;
    scanf("%d %d", &n, &k);
    Euler_sieve(1e6);
    while (n--)
    {
        int x;
        scanf("%d", &x);
        while (x > 1)
        {
            int i = v[x];
            int tmp = 1;
            int flag = -1;
            if (k % i == 0)flag = 0;
            while (x % i == 0)
            {
                x /= i;
                if (flag == 0)
                {
                    tmp *= i;
                    if (k % tmp == 0 && k % (tmp * i))
                    {
                        k /= tmp;
                        flag = 1;
                    }
                }
            }
        }
    }
    if (k > 1)
        printf("No");
    else printf("Yes");
    return 0;

}

CF664A Complicated GCD

\(gcd(i,i+1)==1\),水题

CF762A k-th divisor

暴力分解

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 1e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

vector<ll>yz;

int main()
{
    ll n, k;
    cin >> n >> k;
    ll lim = sqrt(n);
    for (int i = 1; i <= lim; i++)
    {
        if (n % i == 0)
            yz.push_back(i);
    }
    for (int i=yz.size()-1;i>=0;i--)
    {
        if (n / yz[i] != yz[i])
            yz.push_back(n / yz[i]);
    }
    if (k > yz.size())
        cout << -1 << endl;
    else cout << yz[k - 1] << endl;
    return 0;

}

CF776B Sherlock and his girlfriend

构造,素数涂1合数涂0

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 1e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int p[maxn], v[maxn], cnt = 0;

void elshai(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!v[i]) 
            p[++cnt] = i, v[i] = i;
        for (int j = 1; j <= cnt; j++)
        {
            if (p[j] > v[i] || p[j] > n / i)break;
            v[i * p[j]] = p[j];
        }
    }
}

int col[maxn], ans = 0;

int main()
{
    fastio;
    elshai(1e6 + 5);
    int n;
    cin >> n;
    int ans = 1;
    for (int i = 2; i <= n + 1; i++)
    {
        col[i] = (v[i] == i ? 1 : 2);
        if (col[i] == 2)
            ans = 2;
    }
    cout << ans << endl;
    for (int i = 2; i <= n + 1; i++)
        cout << col[i]<<" ";
    return 0;

}

P5431 【模板】乘法逆元2

不算模版题。由于n<=5e6需要先预处理,把求和式子通分,然后求前缀后缀积,最后求逆元。(还要加个快读,数组也不能全ll,因为空间只有128MB)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 5e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c>'9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + c - '0', c = getchar();
    return f * x;
}

int qpow(int x, int y)
{
    x %= mod;
    ll res = 1;
    while (y)
    {
        if (y & 1)res = res * x % mod;
        x = 1ll * x * x % mod;
        y >>= 1;
    }
    return res%mod;
}

int inv(int x)
{
    return qpow(x, mod - 2) % mod;
}

ll a[maxn];
int pre[maxn], suf[maxn], K[maxn];

int main()
{
    //fastio;
    ll n,  k;
    n = read(), mod = read(), k = read();
    pre[0] = suf[n + 1] = K[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        a[i] = read();
        pre[i] = pre[i - 1] * a[i] % mod;
        K[i] = K[i - 1] * k % mod;
    }
    for (int i = n; i >= 1; i--)
        suf[i] = suf[i + 1] * a[i] % mod;
    ll ans = 0;
    ll und = inv(pre[n]);
    for (int i = 1; i <= n; i++)
        ans = (ans + (K[i] * (1ll * pre[i - 1] * suf[i + 1] % mod) % mod) * und) % mod;
    printf("%lld", ans);
    return 0;

}

P3807 【模板】卢卡斯定理

套公式:\(C(n,m)=C(n/p,m/p)*C(n\%p,m\%p)\)

关于为什么不能线性求(因为数据很小)

因为递推fac的时候,p小于n+m,这时候fac[p]到fac[n+m]都会变成0,之后带有这些fac的项也都会变成0;

实际上C(n,m)=n!/m!/(n-m)!中fac中包含因子p的项可能会被消去,此时%p就不一定等于0了,但之前预处理的时候把这些项都标记成了0,这样答案就不对了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define pii pair<int,int>
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 5e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

ll qpow(ll x, ll y)
{
    x %= mod;
    ll res = 1;
    while (y)
    {
        if (y & 1)res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res%mod;
}

ll inv(ll x)
{
    return qpow(x, mod - 2) % mod;
}

ll a[maxn];
ll fac[maxn];

ll C(int n, int m)
{
    if (n < m)return 0;
    if (m == 0)return 1;
    if (n < mod)
        return fac[n] * inv(fac[m]) * inv(fac[n - m]) % mod;
    return C(n / mod, m / mod) * C(n % mod, m % mod) % mod;
}

int main()
{
    fastio;
    int t;
    cin >> t;
    fac[0] = 1;

    while (t--)
    {
        int n, m;
        cin >> n >> m >> mod;
        for (int i = 1; i < mod; i++)
            fac[i] = fac[i - 1] * i % mod;
        cout << C(n + m, n)%mod << endl;
    }
    return 0;

}

CF632D Longest Subsequence

题意:给出n个数,要求选出尽可能多的数,满足它们的最小公倍数不大于m。允许数列里没数,此时这个数列的最小公倍数为1。

\(n,m<={10}^{6}, a_i <= {10}^{9}\)

两个数的lcm必然大于其中任意一个数

所以可以把\(a_i > m\)全部筛除;

剩下的a_i可以用类似埃筛的方法把所有可以整除a_i的小于等于m的数x的\(res[a[i]*j]+=cnt[a[i]]\)

最后从小到大枚举lcm,找到res[i]最大的第一个数就是可以凑出的最大lcm

结论:因为这个数是最小的一个可以被最多数整除的数,\(lcm(a_1,a_2,...,a_n)\)可以被其中任意一个\(a_i\)整除

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
const int inf = 1e9 + 7;
const ll lnf = 1e18 + 7;
const int maxn = 5e6 + 10;
ll mod = 1e9 + 7;
double eps = 1e-6;

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int cnt[maxn], res[maxn];

int main()
{
    fastio;
    int n, m;
    cin >> n >> m;
    set<int>s;
    vector<int>a(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if (a[i] > m)continue;
        s.insert(a[i]);
        cnt[a[i]]++;
    }
    for (auto i : s)
    {
        for (int j = i; j <= m; j += i)
            res[j] += cnt[i];
    }
    int lcm = 1, ans = 0;
    for (int i = 1; i <= m; i++)
        if (res[i] > ans)
            ans = res[i], lcm = i;
    cout << lcm << " " << ans << endl;
    for (int i = 1; i <= n; i++)
    {
        if (lcm % a[i] == 0)
            cout << i << " ";
    }
    return 0;

}
posted @ 2021-04-27 22:43  Lecoww  阅读(115)  评论(0编辑  收藏  举报