数学专题整理

数学专题整理

学习清单

快速幂、矩阵、数论(逆元、容斥、素数筛、高斯消元)、FFT

归纳整理

GCD与LCM

  • GCD计算方式来自公式gcd(a,b)=gcd(b,a%b)
int gcd(int a, int b){
    return b>0? b : a%b;
}
  • LCM计算方式来自性质ab=gcd(a,b)*lcm(a,b)
int lcm(int a, int b){
    return a * b / std::__gcd(a, b);
}
  • 还有一个性质lcm(m*a,m*b)=m*gcd(a,b)

A - GCD LCM

UVA - 11388

题解

给出两个数的GCD和LCM,求这两个数。
从这里学到了GCD和LCM的计算方法和性质,归纳在上面。由性质可以得到,如果存在的话那么L肯定能够被G整除,既然能够整除那么这两个数就可以是G和L

代码

#include 
int main(){
    int t, g, l;
    scanf(“%d”, &t);
    while (t--){
        scanf("%d%d", &g, &l);
        if (l%g) printf("-1\n");
        else printf("%d %d\n", g, l);
    }
    return 0;
}

B - Benefit

UVA - 11889

题意

给出A和C两个数,求一个B,使LCM(A,B)=C
一开始觉得只要B=C/A就行,但是会有问题,比如说A=12,B=16,C=48这个情况,如果只简单地除一下,结果是受到了A的影响的。需要在叠加上它们的最大公约数就可以了。

代码

#include 
#include 

int main(){
    int t, a, c, b, g;
    scanf("%d", &t);
    while (t--){
        scanf("%d%d", &a, &c);
        if (c%a){
            printf("NO SOLUTION\n");
            continue;
        }
        b = c / a;
        g = std::__gcd(a, b);
        while (g != 1){
            b *= g;
            a /= g;
            g = std::__gcd(a, b);
        }
        printf("%d\n", b);
    }
    return 0;
}

C - How do you add?

UVA - 10943

题意

DP。
m拆分成k个整数有多少种拆法。
因为个数不多所以直接打表。……个数多了也不会做了。
dp[i][j]=sum(dp[i-1][k]) (0

代码

#include 
#include 

int main(){
    int a, b, dp[101][101];
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i <= 100; ++i)
        dp[1][i] = 1;
    for (int i = 2; i <= 100; ++i)
        for (int j = 0; j <= 100; ++j)
            for (int k = 0; k <= j; ++k)
                dp[i][j] = (dp[i][j] + dp[i-1][k]) % 1000000;
    
    while (scanf("%d%d", &a, &b), a+b)
        printf("%d\n", dp[b][a]);
    
    return 0;
}

B - Discovering Gold

LightOJ - 1030

题意

数学期望。
你在洞中最深处(位置1),洞内的坐标是[1, n]。你有一颗色子,抛一下,色子上的数字代表你会到达之后的哪一个位置。洞地上有数量不等的黄金,求能得到黄金的期望。
期望公式:

d = p[i]+�(p[i]+p[i+1]+p[i+2]+p[i+3]+p[i+4]+p[i+5]+p[i+6])/6

代码

/******************************
 *File name: LightOJ1030.cpp
 *Author: wzhzzmzzy
 *Created Time: 五  4/14 14:51:32 2017
 *TODO: LightOJ - 1030 概率
******************************/
#include 
int main(){
    int t, cas = 0;
    scanf("%d", &t);
    while (t--){
        int n, m[105], sum[105] = {};
        double dp[105] = {};
        scanf ("%d", &n);
        for (int i = 1; i <= n; ++i){
            scanf("%d", m+i);
            dp[i] = m[i];
            sum[i] = sum[i-1] + m[i];
        }
        for (int i = n-1; i >= 1; --i){
            int len = i < n-5? 6 : n - i;
            for (int j = i+1; j <= i+len; ++j)
                dp[i] += dp[j] / len;
        }
        printf("Case %d: %lf\n", ++cas, dp[1]);
    }
    return 0;
}

D - Just another Robbery

LightOJ - 1079

题意

概率、DP。01背包。

代码

/******************************
 *File name: LightOJ1079.cpp
 *Author: wzhzzmzzy
 *Created Time: 五  4/14 15:57:03 2017
 *TODO: LightOJ-1079 期望、dp
******************************/

#include 
#include 
#include 
#include 

using namespace std;

struct bank{
    double p;
    int m;
}ba[105];
double dp[102][10005], p;
int sum, n;

void solve(){
    for (int i = 1; i <= sum; ++i)
        dp[0][i] = (double)-1;
    dp[0][0] = 0;

    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= sum; ++j){
            dp[i][j] = dp[i-1][j];
            if (j - ba[i].m >= 0 && fabs(dp[i-1][j-ba[i].m]+1) > (double)1e-7){
                if (fabs(dp[i][j]+1)>(double)1e-7)
                    dp[i][j] = min(dp[i][j], dp[i-1][j-ba[i].m] + (1-dp[i-1][j-ba[i].m])*ba[i].p);
                else
                    dp[i][j] = dp[i-1][j-ba[i].m] + (1-dp[i-1][j-ba[i].m])*ba[i].p;
            }
        }
}

int main(){
    int t, cas = 0;
    scanf("%d", &t);
    while (t--){
        sum = 0;
        scanf("%lf%d", &p, &n);
        for (int i = 1; i <= n; ++i){
            scanf("%d%lf", &ba[i].m, &ba[i].p);
            sum += ba[i].m;
        }
        solve();
        for (int i = sum; i >= 0; --i){
            if (dp[n][i] >= 0.0 && p - dp[n][i] > (double)1e-7){
                printf("Case %d: %d\n", ++cas, i);
                break;
            }
        }
    }
    return 0;
}

E - Birthday Paradox

LightOJ - 1104

题意

暴力、概率。
我的做法是暴力解,因为最多只要不到400人就可以满足条件了。直接暴力跑,卡着TLE的时间过了。

代码

/******************************
 *File name: LightOJ1104.cpp
 *Author: wzhzzmzzy
 *Created Time: 五  4/14 21:55:53 2017
 *TODO: LightOJ-1104 暴力
******************************/

#include 
int main(){
    int t, cas = 0, n;
    scanf("%d", &t);
    while (t--){
        int ans = 0;
        scanf("%d", &n);
        
        for (int i = 2; i < 400; ++i){
            double sp = 1;
            for (int j = 1; j < i; ++j){
                sp *= n - j;
                sp /= n;
            }
            if (sp <= 0.5){
                ans = i;
                break;
            }
        }

        printf("Case %d: %d\n", ++cas, ans-1);
    }
}

你可能感兴趣的:(数学专题整理)