洛谷【数学1】基础数学问题

洛谷的专题qwqqqqq(乱序按心情做也不一定做得完= =)
三分钟热度就有三分钟的收获_(:з」∠)_
但是我永远喜欢算法

P1143 进制转换

思路:先转为十进制,再转为目标进制。
转十进制:先乘再模
十转其他:先模再除

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n, m, x;
char a[111];

int main()
{
    cin >> n >> a >> m;
    x = 0;
    for(int i = 0; a[i] ;i ++)
    {
        x *= n;
        if(a[i] >= '0' && a[i] <= '9') x += a[i] - '0';
        else x += a[i] - 'A' + 10;
    }
    int idx = 0;
    while(x)
    {
        int t = x % m;
        x /= m;
        if(t < 10) a[idx] = '0' + t;
        else a[idx] = 'A' + (t - 10);
        idx ++;
    }
    for(int i = idx - 1;i >= 0; i--) cout << a[i];
    return 0;
}

P1469 找筷子

思路:奇妙转为异或和
因为有内存限制,而且数据是1e7实在太多,开始是想unique离散化,然后快乐地MLE了一发(?)
理智分析,一个数异或自己就是0,就是说:x ^ x == 0 ; 再加上,0异或任何数都是任何数本身。也就是说所有输入的异或和最后就剩那个寡王。(挺妙的一开始没想到)
还有就是因为输入太多了建议1e6以上就用scanf而不是cin。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int main()
{
    int n, a, ans;
    scanf("%d", &n);
    ans = 0;
    for(int i = 0;i < n; i++)
    {
        scanf("%d",&a);
        ans ^= a;
    }
    printf("%d\n", ans);
    return 0;
}

P1100 高低位交换

思路:题目说啥就写啥_(:з」∠)_
可能吗?不可能。
开始直接模拟写的,然后点了一下题解。
位运算的话好像代码会巨短!

先给出模拟的代码
顺带一提不开long long是会wa的(别问怎么知道的)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

int a[66];

int main()
{
    ll n;
    scanf("%lld", &n);
    int idx = 32;
    while(n)
    {
        a[idx --] = n % 2;
        n /= 2;
    }
    for(int i = 1;i <= 16; i++)
    {
        swap(a[i], a[16 + i]);
    }
    n = 0;
    for(int i = 1;i <= 32; i++)
    {
        n *= 2;
        n += a[i];
    }
    printf("%lld\n", n);
    return 0;
}

然后是位运算的代码
思路:C++的unsigned int正好32位,所以位运算溢出的部分不需要管。
(所以涉及到二进制可以考虑一下位运算?)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef unsigned int ui;

int main()
{
    ui n;
    cin >> n;
    cout << (n << 16) + (n >> 16) << endl;
    return 0;
}

P1017 进制转换

思路:负数进制的进制转换和普通的进制转换没啥差别,主要是取余的时候会出现负数,需要处理一下,把余数变成正数,然后把补充余数的部分从原数中减掉就好啦_(:з」∠)_

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

char a[66];

int main()
{
    int n, r;
    scanf("%d%d", &n, &r);
    int x = n;
    int idx = 0;
    while(n)
    {
        int t = n % r;
        if(t < 0)
        {
            n += r;
            t -= r;
        }
        n /= r;
        if(t < 10) a[idx ++] = t + '0';
        else a[idx ++] = t - 10 + 'A';
    }
    printf("%d=", x);
    for(int i = idx - 1;i >= 0; i--) printf("%c", a[i]);
    printf("(base%d)", r);
    return 0;
}

P2660 zzc 种田

思路:简单贪心,有点像gcd,每次选最大的正方形除尽就好

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;

int main()
{
    ull x, y, ans;
    cin >> x >> y;
    ans = 0;
    if(x < y) swap(x, y);
    while(x && y)
    {
        ans += 4 * (x / y) * y;
        x %= y;
        swap(x, y);
    }
    cout << ans << endl;
    return 0;
}

P4057 [Code+#1]晨跑

思路:就是很简单的求三个数的最小公倍数,最小公倍数等于两数的乘积除以最大公约数,习惯上要先除再乘防爆

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

ll gcd(ll x, ll y)
{
    if(x % y == 0) return y;
    return gcd(y, x % y);
}
int main()
{
    ll a, b, c, ans;
    cin >> a >> b >> c;
    ans = a / gcd(a, b) * b;
    ans = ans / gcd(ans, c) * c;
    cout << ans << endl;
    return 0;
}

P3383 【模板】线性筛素数

思路:线性筛的核心就是说——n只会被它的最小质因子筛掉;
分为两步:
①从小到大枚举所有质数;
②每次把当前的质数和 i 的乘积筛掉;
当 i % p[j] == 0,说明 p[j] 一定是p[j] * i的最小质因子;
否则,p[j] 一定小于 i 的所有质因子,p[j] 也一定是 p[j] * i 的最小质因子;
而对于一个合数,假设 p[j] 是 x 的最小质因子,则当 i 枚举到 x / p[j] 时,x 就会被筛掉;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e8 + 10;
int p[6000010], idx;
bool st[maxn];

int main()
{
    int n, q, k;
    scanf("%d%d", &n, &q);
    idx = 0;
    memset(p, 0, sizeof(p));
    memset(st, 0, sizeof(st));
    for(int i = 2;i <= n; i++)
    {
        if(!st[i]) p[idx ++] = i;
        for(int j = 0;p[j] <= n / i; j++)
        {
            st[p[j] * i] = true;
            if(i % p[j] == 0) break;
        }
    }
    for(int i = 0;i <  q; i++)
    {
        scanf("%d", &k);
        printf("%d\n", p[k - 1]);
    }
    return 0;
}

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

思路:数据范围无比友善,所以暴力就行
因为P和Q可以交换,所以特殊处理一下完全平方数就好

#include <iostream>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int gcd(int a, int b)
{
    if(a % b == 0) return b;
    return gcd(b, a % b);
}

int main()
{
    int x, y;
    cin >> x >> y;
    int ans = 0;
    int s = x * y;
    int flag = 0;
    for(int i = 1;i <= s / i; i++)
    {
        if(s % i == 0 && gcd(i, s / i) == x)
        {
            ans ++;
            if(i * i == s) flag = 1;
        }
    }
    if(flag)
    {
        if(ans) cout << ans * 2 - 1 << endl;
        else cout << 1 << endl;
    }
    else cout << ans * 2 << endl;
    return 0;
}

P1403 [AHOI2005]约数研究

思路:很简单,和筛素数差不多的思想,就是从小到大枚举,然后把所有倍数的约数个数 + 1,加一下就好啦。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 10;

int sum[maxn];

int main()
{
    int n;
    scanf("%d", &n);
    int res = 0;
    for(int i = 1;i <= n; i++)
    {
        for(int j = 1;j <= n / i; j++)
        {
            sum[i * j] ++;
        }
        res += sum[i];
    }
    printf("%d\n", res);
    return 0;
}

P1572 计算分数

思路:拿手模拟就行,输入直接scanf读,不用处理字符串这样麻烦。然后wa的两发的原因在于,一次没想整除,一次没想分母为负,我觉得我就是傻蛋= =,当场退役算了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int gcd(int a, int b)
{
    if(a % b == 0) return b;
    return gcd(b, a % b);
}

int main()
{
    int x, y, p, q;
    scanf("%d/%d", &x, &y);
    while(~scanf("%d/%d", &p, &q))
    {
        int k = gcd(y, q);
        x = q / k * x;
        p = y / k * p;
        x = x + p;
        y = y / k * q;
        k = gcd(x, y);
        x = x / k;
        y = y / k;
    }
    if(y < 0)
    {
        x *= -1;
        y *= -1;
    }
    if(x % y == 0) printf("%d\n", x / y);
    else printf("%d/%d\n",x, y);
    return 0;
}

P3913 车的攻击

思路:水题,行列总数 * n 减掉重复的点就行

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;

int r[maxn], c[maxn];

int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1;i <= k; i++) scanf("%d%d", &r[i], &c[i]);
    sort(r + 1, r + 1 + k);
    sort(c + 1, c + 1 + k);
    int len1 = unique(r + 1, r + 1 + k) - 1 - r;
    int len2 = unique(c + 1, c + 1 + k) - 1 - c;
    printf("%lld\n", (ll)n * (len1 + len2) - (ll)len1 * len2);
    return 0;
}

P1246 编码

思路:神奇的组合数叭算是
因为一共只有26个字母,且只有6位,所以可以预处理出26以内的所有组合数。对于给定编码的每一位进行讨论,因为题目规定了必须升序,所以相当于枚举每一位,然后加上合法的组合数,wa了很多发因为忘记处理首位的边界问题。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

char a[11];

int c[27][27];

void init()
{
    for(int i = 0;i <= 26; i++)
    {
        for(int j = 0;j <= i; j++)
        {
            if(!j) c[i][j] = 1;
            else c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
        }
    }
}

int main()
{
    init();
    scanf("%s", a + 1);
    int ans = 0;
    int n = strlen(a + 1);
    int flag = 0;
    for(int i = 2;i <= n; i++)
    {
        if(a[i] <= a[i - 1])
        {
            flag = 1;
            break;
        }
    }
    if(flag) printf("0\n");
    else
    {
        for(int i = 1;i < n; i++) ans += c[26][i];
        for(int i = 1;i <= n; i++)
        {
            int j;
            if(i == 1) j = 1;
            else j = a[i - 1] - 'a' + 2;
            while(j < a[i] - 'a' + 1)
            {
                ans += c[26 - j][n - i];
                j++;
            }
        }
        printf("%d\n", ans + 1);
    }
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值