基础数学问题

目录

P1143 进制转换

P1100 高低位交换

P1866 编号

P3913 车的攻击

P3383 【模板】线性筛素数

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

P1572 计算分数

P4057 [Code+#1] 晨跑

P2651 添加括号III

 P2660 zzc 种田

P1403 [AHOI2005] 约数研究

 P1469 找筷子

P1246 编码

P2926 [USACO08DEC] Patting Heads S

P1835 素数密度

P1414 又是毕业季II


P1143 进制转换

inline void solve()
{
    int n, m;
    string s;
    cin >> n >> s >> m;
    int sum = 0, k = 0;
    // 将n进制转换为10进制
    for (int i = 0; i < s.size(); i++)
    {
        if (s[i] < 'A')
        {
            k = (s[i] - '0') * pow(n, s.size() - i - 1);
            sum += k;
        }
        else
        {
            k = (s[i] - 'A' + 10) * pow(n, s.size() - i - 1);
            sum += k;
        }
    }
    // 将10进制转换为m进制
    vector A;
    while (sum > 0)
    {
        A.pb(sum % m);
        sum /= m;
    }
    for (int i = A.size() - 1; i >= 0; i--)
    {
        if (A[i] < 10)
            cout << A[i];
        else
            printf("%c", A[i] - 10 + 'A'); // 注意要用%c
    }
}

P1100 高低位交换

inline void solve()
{
    unsigned int n;  //范围是2^32,signed是2^31
    cin >> n;
    cout << (n >> 16) + (n << 16);
}

P1866 编号

const int mod = 1e9 + 7;
int a[51];

inline void solve()
{
    int n;
    LL s = 1;
    cin >> n;
    ff(i, n) cin >> a[i];
    sort(a + 1, a + n + 1);
    ff(i, n)
    {
        s *= (a[i] - i + 1);
        s %= mod;
    }
    cout << s;
}

P3913 车的攻击

第一点:在unique之前必须保证去重数组有序,也就是得sort一下。
第二点:unique并不会生成一个新的数组,而是将原数组多余的部分“移”到了数组之后,同时unique本身还会返回一个指针,指向去重之后的最后一位。

利用c++可以指针相加减的特点,我们可以通过 unique-数组指针 来知道去重之后数组的“大小”

const int N = 1e6 + 10;
LL a[N], b[N];
LL n, k;
inline void solve()
{
    scanf("%lld%lld", &n, &k);

    f(i, k) scanf("%lld%lld", &a[i], &b[i]);
    // cin >> a[i] >> b[i];
    sort(a, a + k);
    sort(b, b + k);
    LL x = unique(a, a + k) - a;
    LL y = unique(b, b + k) - b;
    printf("%lld", n * n - (n - x) * (n - y));
}

P3383 【模板】线性筛素数

const int N = 1e8 + 10;
int primes[N], cnt;
bool st[N];
void get_primes(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
        {
            primes[++cnt] = i; // i如果是质数,就加到数组中
        }

        for (int j = 1; primes[j] <= n / i; j++) // 从小到大枚举所有质数
        {
            st[primes[j] * i] = true; // 把当前的质数和i的乘积筛掉
            if (i % primes[j] == 0)
                break; // 成立时,primes[j]一定是i的最小质因子,primes[j]也一定是primes[j]*i的最小质因子;不成立时,primes[j]一定小于i的所有质因子,primes[j]也一定是primes[j]*i的最小质因子
        }
    }
}
inline void solve()
{
    int n, m;
    cin >> n >> m;
    get_primes(n);
    while (m--)
    {
        int x;
        cin >> x;
        cout << primes[x] << endl;
    }
}

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

两个数的积等于它们最大公约数和它们最小公倍数的积。公式表示为 a×b=gcd(a,b)×lcm(a,b)

const int N = 1e6 + 10;
LL m, n, ans;
inline void solve()
{
    cin >> m >> n;
    if (m == n)
        ans--;
    n *= m;
    for (LL i = 1; i <= sqrt(n); i++)
    {
        if (n % i == 0 && __gcd(i, n / i) == m)
            ans += 2;
    }
    cout << ans;
}

P1572 计算分数

int a, b, c, d;
int ans1, ans2;

inline void solve()
{
    scanf("%d/%d", &a, &b);
    while ((scanf("%d/%d", &c, &d)) != EOF)
    {
        int gcd = __gcd(b, d);
        int lcm = b * d / gcd;
        ans2 = lcm;
        ans1 = a * (lcm / b) + c * (lcm / d);
        a = ans1 / (__gcd(ans1, ans2));
        b = ans2 / (__gcd(ans1, ans2));
    }
    ans1 = a;
    ans2 = b;
    if (ans2 < 0)
    {
        ans1 =- ans1;
        ans2 =- ans2;
    }
    if (ans2 == 1)
        printf("%d\n", ans1);
       
    else
        printf("%d/%d\n", ans1, ans2);
}

P4057 [Code+#1] 晨跑

inline void solve()
{
    LL a, b, c;
    cin >> a >> b >> c;
    cout << a * b * c / __gcd(b, c) / __gcd(a, b * c / __gcd(b, c));
}

P2651 添加括号III

a1肯定是分子,a2肯定是分母

a1/(a2/a3/a4/...)=a1a3a4.../a2,所以我们只要确认a1a3a4.../a2是否是整数。

如果进行约分,知道a2能被约分成1,那么就是整数。

const int N = 1e4 + 10;
int a[N];
inline void solve()
{
    int n;
    cin >> n;
    cin >> a[1] >> a[2];
    a[2] /= __gcd(a[1], a[2]);
    for (int i = 3; i <= n; i++)
    {
        cin >> a[i];
        a[2] /= __gcd(a[i], a[2]);
    }
    if (a[2] == 1)
        cout << "Yes" << endl;
    else
        cout << "No" << endl;
}

 P2660 zzc 种田

inline void solve()
{
    LL x, y;
    cin >> x >> y;
    LL ans = 0;
    while (x && y)
    {
        swap(x, y); // x是长,y是宽
        ans += 4 * y * (x / y);
        x %= y;
    }
    cout << ans << endl;
}

P1403 [AHOI2005] 约数研究

[1,n]里约数有i的个数是⌊n/i​⌋下取整

约数表如下所示

基础数学问题_第1张图片

inline void solve()
{
    int n;
    cin >> n;
    LL ans = 0;
    ff(i, n)
    {
        ans += n / i;
    }
    cout << ans;
}

优化: 很多⌊n/i​⌋下取整都是一样的,i跳到⌊n/j​⌋=⌊n/i​⌋+1的位置

inline void solve()
{
    int n, ans = 0;
    cin >> n;
    for (int i = 1; i <= n;)
    {
        int j = n / (n / i);
        ans += (n / i) * (j - i + 1);
        i = j + 1;
    }
    cout << ans;
}

 P1469 找筷子

const int N = 1e7 + 10;
int a[N], b[N];
set s;
inline void solve()
{
    int n;
    cin >> n;
    ff(i, n)
    {
        cin >> a[i];
        b[a[i]]++;
        s.insert(a[i]);
    }

    for (auto i : s)
    {
        if (b[i] % 2 != 0)
        {
            cout << i << endl;
            break;
        }
    }
}

基础数学问题_第2张图片

空间限制为 4 Mb的时候,开一个10^7的数组就MLE了。

 异或运算

异或的两个小小的性质:

  1. k 个相同的数的异或和,当 k 为奇数时,结果是这个数本身,否则结果是 0。
  2. 任何数与 0 的异或值是它本身。

基础数学问题_第3张图片

inline void solve()
{
    int n;
    cin >> n;
    int ans = 0;
    ff(i, n)
    {
        int x;
        cin >> x;
        ans ^= x;
    }
    cout << ans;
}

P1246 编码

模拟:

inline void solve()
{
    string s;
    cin >> s;
    int sl = s.size();
    int a[8];
    for (int i = 0; i < sl; i++)
        a[i] = s[sl - i - 1] - 'a' + 1;
    int t = 0;
    int b[8] = {0};
    while (++t)
    {

        b[0]++;
        int k = 0;
        for (int i = 0; i < 8; i++)
        {
            if (b[i] > 26 - i)
            {
                k++;
                b[i + 1]++;
            }
            else
                break;
        }
        for (int i = k - 1; i >= 0; i--)
        {
            b[i] = b[i + 1] + 1;
        }
        int flag = 0;
        for (int i = 0; i < sl; i++)
        {
            if (a[i] != b[i])
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0)
        {
            cout << t << endl;
            break;
        }

        if (b[6])
        {
            cout << "0" << endl;
            break;
        }
    }
}

打表:

map m;
int ans = 1;
void qwe(int res, char c, string s)
{
    if (res == 0)
    {
        m[s] = ans;
        ans++;
        return;
    }
    if (c == 'z' + 1)
        return;
    for (int i = 0; c + i <= 'z' - (res - 1); i++) // 要求不重复
    {
        qwe(res - 1, char(c + i) + 1, string(s + char(c + i)));
    }
}
inline void solve()
{
    qwe(1, 'a', "");
    qwe(2, 'a', "");
    qwe(3, 'a', "");
    qwe(4, 'a', "");
    qwe(5, 'a', "");
    qwe(6, 'a', "");
    string s;
    cin >> s;
    cout << m[s];
}

P2926 [USACO08DEC] Patting Heads S

const int N = 1e6 + 10;
int a[N], b[N], cnt[N];
inline void solve()
{
    int n;
    cin >> n;
    int maxn = 0;
    ff(i, n)
    {
        cin >> a[i];
        b[a[i]]++; // 存a[i]出现的次数
        maxn = max(maxn, a[i]);
    }
    ff(i, maxn)
    {
        if (b[i] == 0)
            continue;
        for (int j = 1; i * j <= maxn; j++)
            cnt[i * j] += b[i]; // 枚举i的倍数,同j+=i;cnt[j]+=b[i];
    }
    ff(i, n) cout << cnt[a[i]] - 1 << endl; // 不能拍自己
}

P1835 素数密度

// 欧拉筛
const int N = 1e5 + 10;
int primes[N], cnt; // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉
void get_primes(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
            primes[cnt++] = i;
        for (int j = 0; primes[j] * i <= n; j++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
                break;
        }
    }
}
// 区间范围,因为我们无法完全映射所有的区间,只能采用类似于偏移的办法对某段区间整体偏移L进行描述。
// 否则空间上的限制就先达到了,无法用计算机模拟了。
const int M = 10000010;
int a[M]; // 记录偏移后的数据是不是合数,1:合数;0:质数。a[i]表示L+i是不是合数, 有一个偏移量L
inline void solve()
{
    // 筛出50000之内的所有质数
    get_primes(50000); // R开根号的极限也小于50000
    // 问:为啥要开LL,开INT不行吗?
    // 答:不行,因为下面的运算中可能存在加法,如果是极限的整数,再加一下就会爆INT。
    LL L, R;
    cin >> L >> R;
    // 特判,防止第11个测试点WA掉。
    if (L == 1)
        L = 2;

    // 遍历已知的质数列表
    for (int i = 0; i < cnt; i++)
    {
        // start:找到开始筛的数字
        // 【大于L,并且是p的倍数,最小整数是多少?】
        LL start = max(2ll, (L - 1) / primes[i] + 1) * primes[i];
        // 成倍的质数筛出掉
        for (LL j = start; j <= R; j += primes[i])
            a[j - L] = 1; // 标识为质数
    }

    // 结果
    int ans = 0;
    for (LL i = L; i <= R; i++)
        if (!a[i - L])
            ans++;
    cout << ans << endl;
}

P1414 又是毕业季II

const int N = 1e6 + 10;
int cnt[N]; // c[i]表示i作为因子的次数
inline void solve()
{
    int n;
    cin >> n;
    int t = 0;
    ff(i, n)
    {
        int x;
        cin >> x;
        t = max(t, x); // 记录目前最大能力值
        for (int i = 1; i <= sqrt(x); i++)
        {
            if (x % i == 0) // 有约数
            {
                cnt[i]++; // i作为因子的次数++
                if (x != i * i)
                    cnt[x / i]++; // 如果不是平方,x/i也是因子;如果x是i的平方只记录i作为一次因子
            }
        }
    }
    int x = t;
    ff(i, n)
    {
        while (cnt[x] < i) // cnt[x]>=i时停止
            x--;
        cout << x << endl;
    }
}

 

你可能感兴趣的:(洛谷,算法,数据结构)