数学专题整理
学习清单
快速幂、矩阵、数论(逆元、容斥、素数筛、高斯消元)、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);
}
}