第二届齐鲁工业大学(山东省科学院)与山东师范大学ICPC大学生程序设计竞赛联赛 [官方题解]
题目目录
- A. A+B Problem
- B. 77777
- C. Merge
- D. 魔法少女:承
- E.学妹的任务
- F. AKIE's Penalty
- G. A-B Problem
- H. 翻转队列
- I. 魔法少女:转
- J. 挑选队列
- K. 魔法少女:合
- L. 神奇的转盘
- M. AAO
- N. 来自异世界的巧克力
- O. hina的迷宫
首先…作为命题和验题组负责人对此次比赛中出现的各种锅而影响到参赛选手的比赛体验表示十分抱歉,几个突发状况难以进行事先预测并得到有效解决TvT,望理解海涵。
对此题解的任何问题请联系QQ:1098509291指正/说明。
A. A+B Problem
题意: 找一个最小的整数K(2≤K≤9)K(2\leq K \leq 9)K(2≤K≤9)满足(a+b)10=(n)K(a+b)_{10}=(n)_K(a+b)10=(n)K,找不到则输出−1-1−1
思路: 模拟。枚举222到999进制,判断nnn是否可以是这个进制的数,如果可以就把nnn转化成101010进制数判断是否与a+ba+ba+b相等。
//A+B Problem Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int a,b;
string n;
int main(){cin>>a>>b>>n;for(int i=2;i<=9;i++){int sum=0;for(int j=n.length()-1,k=1;j>=0;j--,k*=i){if(n[j]-'0'>=i){sum=-1;break;}sum+=k*(n[j]-'0');}if(sum==a+b){cout<<i;return 0;}}cout<<-1;
}
B. 77777
题意: 问所给的小写串SSS中是否能找到一个子串,其中至少有一个字母的出现次数恰好等于777
思路: 贪心。遍历一遍串SSS,只要整个串里有一个字母出现的次数≥7\geq 7≥7,就一定能找到一个合法的子串使得其中至少有一个字母的出现次数恰好等于777。
//77777 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int n,cnt[26];
string s;
int main(){cin>>n>>s;for(int i=0;i<n;i++)cnt[s[i]-'A']++;for(int i=0;i<26;i++)if(cnt[i]>=7){printf("YES");return 0;}printf("NO");
}
C. Merge
题意: 给nnn张带权值的卡牌,每次可执行一个操作:选一张卡牌,让它相邻的一张卡牌加或减所选卡牌的权值,并把所选卡牌删掉,求最后剩余的一张卡牌的最大权值。
思路: 贪心。
1° 若至少有一张卡牌权值≥0\geq0≥0,我们可以让这张牌加上所有正权值卡牌,减去所有负权值卡牌,那么答案应该是所有卡牌的权值绝对值之和
2° 若所有卡牌权值都<0<0<0,此时至少有一张卡牌的权值需要取负的贡献,其余卡牌可以取正的贡献(即绝对值)。也就是说我们应该找到一张卡牌,让它去减其他所有卡牌。所以要最大化最终权值,应该找权值最大的卡牌,去减其他所有卡牌。答案也就是所有卡牌的权值绝对值之和 - 最大的卡牌权值*2
//Merge Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+7;
int n;
LL ans,x,k=-1e9-1;
int main(){cin>>n;for(int i=1;i<=n;i++){scanf("%lld",&x);ans+=(x>0?x:-x);k=max(k,x);} if(n==1)cout<<k;else if(k>=0)cout<<ans;else cout<<ans+k+k;
}
D. 魔法少女:承
题意: 给定每颗高、低纯度结晶的回复理性值和纯粹度,找一种使用高、低纯度结晶的个数,使得理性值回满,平均纯粹度≥60%\geq60\%≥60%,尽可能节约高纯度结晶,其次节约低纯度结晶。
思路: 两层for循环枚举使用两种结晶的个数,判断是否合法,更新最小值。
//魔法少女:承 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int T,a1,b1,a2,b2;
int main(){cin>>T;while(T--){cin>>a1>>b1>>a2>>b2;int ans1=INT_MAX,ans2=INT_MAX;for(int i=0;i<=100;i++)for(int j=0;j<=100;j++)if(i*a1+j*a2>=100&&(i*b1+j*b2)/(i+j)>=60){if(i<ans1||(i==ans1&&j<ans2)){ans1=i;ans2=j;}}printf("%d %d\n",ans1,ans2);}
}
E.学妹的任务
题意: 依次拼接字符串,对当前已拼接的字符串的后缀和下一个待拼接的字符串的前缀去重再拼接。
思路: 每次拼接时,枚举下一个待拼接的字符串的所有前缀,用string中的substr函数判断这个前缀是否是已拼接的字符串的后缀,如果是,更新最大重叠长度,然后暴力拼接非重叠部分。
//学妹的任务 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int n;
string s[107],ans;
int main(){cin>>n;for(int i=1;i<=n;i++)cin>>s[i];ans=s[1];for(int i=2;i<=n;i++){int l0=ans.length(),l1=s[i].length(),k=0;for(int j=l1;j;j--){if(l0-j<0)continue;if(s[i].substr(0,j)==ans.substr(l0-j,j)){k=j;break;}}for(int j=k;j<l1;j++)ans+=s[i][j];}cout<<ans;
}
F. AKIE’s Penalty
题意: 给定N个题的提交次数和通过时间,若通过时间TiTiTi为正,则最后一次提交正确,若通过时间TiTiTi为负,则本题未通过。每次错误提交的罚时为20,计算所有通过题目的总罚时。
思路: 若TiTiTi为正,此题罚时为(Ki−1)∗20+Ti(Ki-1)*20+Ti(Ki−1)∗20+Ti,否则罚时为0。累加即可。
//AKIE's Penalty Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=107;
int n,ans,k[N],t;
int main(){cin>>n;for(int i=1;i<=n;i++)scanf("%d",&k[i]);for(int i=1;i<=n;i++){scanf("%d",&t);if(t>=0)ans+=20*(k[i]-1)+t;}printf("%d",ans);
}
G. A-B Problem
题意: 输入两个数,输出A-B。
思路: …[组织语言中.jpg]
//A-B Problem Standard Code [C++]
#include<iostream>
using namespace std;
int main(){int a,b;cin>>a>>b;cout<<a<<"-"<<b;
}
H. 翻转队列
题意: 给两个只包含0/10/10/1的串A,BA,BA,B,每次可以执行操作:从A串中选一个111作为中心,将其相邻的前一个位置的数和后一个位置的数取反(000变成111,111变成000),但开头和结尾位置上的111不能被作为中心。问是否能由AAA串经过若干次操作(或零次)变为BBB串。
思路:
假设AAA串是110111011101,BBB串是011101110111,我们对它们分别按位取异或前缀和,
可以得到前缀和数组SUMASUM_ASUMA: 100110011001,SUMB:0101SUM_B: 0101SUMB:0101
我们选定AAA串中第二个111为中心,进行相邻取反操作,是将其前面第一个数和其后面第一个数取反,AAA会变为011101110111,此时SUMASUM_ASUMA会变为010101010101
可以看出来,如果我们以位置iii为中心,对i−1i-1i−1和i+1i+1i+1取反,对前缀和数组的影响是:SUM[i−1]SUM[i-1]SUM[i−1]取反,SUM[i]SUM[i]SUM[i]取反,对前缀和数组中的其余值其实没有影响。由于AAA串中iii 位置是选择的中心,所以它这一位肯定是111,所以SUMASUM_ASUMA数组中SUMA[i−1]SUM_A[i-1]SUMA[i−1]和SUMA[i]SUM_A[i]SUMA[i]一定不同,那么这两位,肯定一个是111、一个是000。给它们取反,也就是等同于做了交换。
所以,经过若干次操作后,前缀和数组中的000和111的数量不会改变。
并且因为AAA串的首尾的111不能被选为操作中心,所以不管怎么操作,SUMA[n]SUM_A[n]SUMA[n]都不会改变。
所以判断两个串的异或前缀和数组中000和111的数量对应一致,并且两个01串的位异或和相等,那么一定可以通过给AAA串的异或前缀和数组做若干次交换,使其与BBB的异或前缀和数组一致,也就把AAA变得与BBB串一致了,即输出yes。
注意: 由于内存限制为1.5M,所以不可以开2×106长度的int数组,但好像可以开一个相同长度的bitset(未测试)。题解代码未使用数组。
//翻转队列 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int n,sum1,cnt1,sum2,cnt2;
int main(){cin>>n;char x;for(int i=1;i<=n;i++){while(x=getchar(),x!='0'&&x!='1');sum1^=(x=='1');cnt1+=(sum1==1);}for(int i=1,x;i<=n;i++){while(x=getchar(),x!='0'&&x!='1');sum2^=(x=='1');cnt2+=(sum2==1);}if(cnt1==cnt2&&sum1==sum2)printf("yes");else printf("no");
}
I. 魔法少女:转
题意: 找一种五个亡者之怒的使用顺序并指定它们的打击魔兽,使得所有魔兽都被消灭。
思路: 深度优先搜索(dfs),搜索每个魔兽被使用的亡者之怒,若已经被消灭就搜索下一个魔兽,找到答案就输出即可。
//魔法少女:转 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int T,hp[4],a[6],ans[6],flag;
void dfs(int k,int damage){if(flag)return;if(k>3){for(int i=1;i<=5;i++)printf("%d%c",ans[i]," \n"[i==5]);flag=1;return;}if(damage>=hp[k]){dfs(k+1,0);return;}for(int i=1;i<=5;i++)if(!ans[i]){ans[i]=k;dfs(k,damage+a[i]);ans[i]=0;}
}
int main(){cin>>T;while(T--){flag=0;for(int i=1;i<=3;i++)cin>>hp[i];for(int i=1;i<=5;i++)cin>>a[i];dfs(1,0);}
}
J. 挑选队列
题意及思路: Provided By 杨熠辰
本题大意为在 1−n1-n1−n 中挑选出 333 个数使得两两互质或两两不互质的方案数。
我们考虑一个含有 nnn 个点的无向图,如果两个数互质,那么就在这两个数之间连边。这样的话,这题本质上就是求图上三个点的个数,并且要求要么两两连边,要么两两不连边。
由于直接做不是很好做,所以我们考虑容斥,用所有的三元组减掉非法的三元组来求答案。
非法的三元组无非只有两种情况,一种是三个点之间只有一条边,另一种是三个点之间有两条边,如下图:
对于图 111,我们考虑点 111,我们可以发现它与其他的两个点连接且仅连接了一条边,即点 111 与点 222 有连边却与点 333 没有连边,对于点 222 也是。
我们发现图 222 也有这个性质,即三元组中恰好存在两个点,这两个点与除了它自己之外的点恰好连了一条边,另一条没有连边。
于是,我们可以对于每个点,统计一下它的度数,对于点 iii,求所有点的 d[i]×(n−d[i]−1)d[i] \times (n - d[i] - 1)d[i]×(n−d[i]−1) 之和,然后把结果除 222 即是不合法的三元组数。
所以我们下一步只需要求出每个点的度数即可,根据题意,对于点 iii,有
d[i]=∑j=1n[gcd(i,j)=1]=∑d∣iμ(d)⌊nd⌋d[i] = \sum_{j = 1}^n[\gcd(i, j) = 1] = \sum_{d|i}\mu(d)\lfloor\frac nd\rfloor d[i]=j=1∑n[gcd(i,j)=1]=d∣i∑μ(d)⌊dn⌋
但是如果采用枚举因数的方式求 d[i]d[i]d[i] 其最终时间复杂度为 O(nn)O(n\sqrt n)O(nn),所以我们更改枚举方式,对于一个因数 ddd,我们将 μ(d)⌊nd⌋\mu(d)\lfloor\frac nd\rfloorμ(d)⌊dn⌋ 加到其倍数上,这样可以在 nlognn\log nnlogn 的时间复杂度内解决此问题。
//挑选队列 Standard Code [C++]
#include <bits/stdc++.h>const int MAXN = 2e6 + 5;int mu[MAXN], prime[MAXN], notprime[MAXN], n, cnt;
long long f[MAXN];void Shaker() {notprime[1] = mu[1] = 1;for(int i = 2; i <= n; i++) {if(!notprime[i]) prime[cnt++] = i, mu[i] = -1;for(int j = 0; j < cnt && i * prime[j] <= n; j++) {notprime[i * prime[j]] = 1;if(i % prime[j] == 0) {mu[i * prime[j]] = 0;break;}mu[i * prime[j]] = -mu[i];}}
}long long cn3(int n) {return 1LL * n * (n - 1) * (n - 2) / 6;
}int main() {long long ans = 0;scanf("%d", &n);Shaker();for(int i = 1; i <= n; i++) for(int j = i; j <= n; j += i) f[j] += n / i * mu[i];f[1]--;for(int i = 1; i <= n; i++) ans += 1LL * f[i] * (n - f[i] - 1);ans = cn3(n) - ans / 2;printf("%lld\n", ans);return 0;
}
K. 魔法少女:合
题意: 分别给定两棵树的所有连边,判断两棵树是否完全相同(节点、连边都相同)。
思路: 分别对两棵树每条边的两个点升序排序,对所有边按照两端点双关键字排序,然后判断两棵树的边对应相等即可。
//魔法少女:合 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+7;
int n;
pair<int,int>a[N],b[N];
int main(){cin>>n;for(int i=1,x,y;i<n;i++){scanf("%d%d",&x,&y);if(x>y)swap(x,y);a[i]=make_pair(x,y);}for(int i=1,x,y;i<n;i++){scanf("%d%d",&x,&y);if(x>y)swap(x,y);b[i]=make_pair(x,y);}sort(a+1,a+n);sort(b+1,b+n);int flag=1;for(int i=1;i<n&&flag;i++){if(a[i]!=b[i])flag=0;}if(flag)cout<<"RED PILL";else cout<<"BLUE PILL";
}
L. 神奇的转盘
题意: 交互题。有一个2∗22*22∗2的转盘乱序填入了1,2,3,41,2,3,41,2,3,4四个数,每次可以询问xxx nnn,代表位于xxx位置上的数是否为nnn,系统会回答。转盘会在每次询问前顺时针旋转90°90°90° 。要求在666次询问以内,确定当前转盘状态并输出。
思路:
假设起始转盘是:[数字代表转盘中存的数字]
222 333
111 444
(1) 第一次询问前变为:
111 222
444 333
(2) 第二次询问前变为:
444 111
333 222
(3) 第三次询问前变为:
333 444
222 111
对于这个起始转盘,我们可以通过前三次询问本转盘中数字111 (标红色的位置)所出现的位置,分别询问它是否是1/2/31/2/31/2/3,从而确定标红位置是几。
可以看出(1)、(2)、(3)中数字111所在的位置分别是位置1,位置2,位置3
所以我们第一次询问111 111,第二次询问222 222,第三次询问333 333,就可以确定标红色的位置存的数是几。
同理,确定了第一个数,在用剩下的三个数中的任意两个去测试222次**本转盘中数字222接下来出现的两个位置,可以确定本转盘中数字222**的位置存的数是几。
最后再用剩下的两个数去测试本转盘中数字3接下来出现的一个位置,确定本转盘中数字3的位置存的是几。
所以询问恰好3+2+13+2+13+2+1次即可确定转盘内容,并输出当前转盘内容。
以上过程可以用一个函数实现询问。
//神奇的转盘 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int flag[5],a[3][3];
void query(int x,int y,int start,int end){int sum=0;for(int i=1;i<=4;i++)if(!flag[i])sum+=i;for(int i=start,j=1,k;i<=end;i++,j++){while(flag[j])j++;cout<<i<<" "<<j<<endl;sum-=j;cin>>k;if(k==1)a[x][y]=j,flag[j]=1;}if(!a[x][y])a[x][y]=sum,flag[sum]=1;
}
int main(){query(1,2,1,3);query(2,2,1,2);query(2,1,4,4);query(1,1,2020,1024);//后两个参数任意填的,只要进函数之后不执行循环即可cout<<0<<endl;cout<<a[1][1]<<" "<<a[1][2]<<"\n"<<a[2][1]<<" "<<a[2][2];
}
M. AAO
题意: 新创语言。有nnn个数[1,2,...,n][1,2,...,n][1,2,...,n],但输入缺失了一个数(只输入n−1n-1n−1个数),要求找出缺失的数。
思路: 做法很简单,就是计算1+2+...+n1+2+...+n1+2+...+n的值,减去所有输入的数,即是缺失的数。难点在于要用新创语言给定的语句做,建议用C++11自带的
cout<<R"(...)";
语句输出所有新语言的句子,具体写法如下:
//AAO Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int main(){cout<<R"(Initial nYes, BangDreamHey, Y.O.L.O!!!!! nInitial sumROKIROKIROLL nYes, BangDreamInitial nPlease don't say "You are lazy" 1Yes, BangDreamInitial xYes, BangDreamA to Z! A to Z! nHey, Y.O.L.O!!!!! xInitial sumROKIROKIROLL nPlease don't say "You are lazy" xYes, BangDreamInitial nPlease don't say "You are lazy" 1Yes, BangDreamtenkaogo go go for it! sum)";
}
N. 来自异世界的巧克力
题意: 给一个数nnn,要求把它分成 xxx个正奇数 + yyy个正偶数,使得这xxx个奇数和yyy个偶数的和等于nnn。注意,没有要求所分的数各不相同。
思路:
1° 偶数不会改变奇偶性,奇数个奇数的和仍然是奇数,偶数个奇数的和是偶数,所以我们可以先根据nnn的奇偶性和xxx的奇偶性判断是否可以分。
2° xxx个正奇数 + yyy个正偶数的和的最小值应该是xxx个111和yyy个222相加,所以我们可以把 x+2∗yx+2*yx+2∗y 的值与nnn比较,若x+2∗y>nx+2*y > nx+2∗y>n,显然没法分。
所以,判断完可以分之后,我们可以先把nnn分出来xxx个111和yyy个222,剩下的值肯定是一个偶数,我们可以把剩余值加到任意分出来的数上,输出即可。
//来自异世界的巧克力 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int t;
LL n,x,y;
void solve(){scanf("%lld%lld%lld",&n,&x,&y);if((n%2==0&&x%2==1)||(n%2==1&&x%2==0)||x+2LL*y>n){printf("NO\n");return;}printf("YES\n");n-=x+2LL*y;for(int i=1;i<=x;i++)printf("1%c"," \n"[i==x]);for(int i=1;i<y;i++)printf("2 ");printf("%lld\n",n+2);
}
int main(){cin>>t;while(t--)solve();
}
O. hina的迷宫
题意: 给一个字符矩阵的迷宫,其中有已存在的墙壁(不能通过),人物可以向888个相邻的方向走(不可以走到迷宫外),问是否有方案设置不多于kkk个墙壁,使得人物不能从左上角走到右下角。
思路: 在起点的右方、下方、右下方设置字符串即可。设置的时候判断一下原来是否存在墙壁。注意,如果n * m=2 * 2,无论如何设置墙壁,都无法阻挡人物到达右下角(因为终点不能设置墙壁,直接从起点往右下方走一步即可到达)。
//hina的迷宫 Standard Code [C++]
#include<bits/stdc++.h>
using namespace std;
int T,n,m,k;
char s[57][47];
void solve(){cin>>n>>m>>k;for(int i=1;i<=n;i++)scanf("%s",s[i]+1);if(n*m==4)return (void)puts("NO");puts("YES");int cnt=(s[1][2]=='.')+(s[2][1]=='.')+(s[2][2]=='.');cout<<cnt<<"\n";if(s[1][2]=='.')cout<<"1 2\n";if(s[2][1]=='.')cout<<"2 1\n";if(s[2][2]=='.')cout<<"2 2\n";
}
int main(){cin>>T;while(T--)solve();
}
第二届齐鲁工业大学(山东省科学院)与山东师范大学ICPC大学生程序设计竞赛联赛 [官方题解]相关推荐
- 齐鲁工业大学计算机应用技术研究生专业,研究生培养
总体介绍 实验室与高校加强产学研合作,致力于为社会培养和输送高水平.复合型的信息化人才.从2003年开始与齐鲁工业大学.山东科技大学高等院校合作,联合开办硕士点:2017年起,在齐鲁工业大学和山东省科 ...
- 齐鲁工业计算机考研分数线,齐鲁工业大学2021考研分数线已公布
2021考研国家线已公布,接下来迎来的是考研复试分数线,复试分数线决定游走在边缘的考生是否能够顺利进入复试环节,中公考研为大家整理"齐鲁工业大学2021考研分数线已公布",一起关注 ...
- 新增数学与人工智能学部,考数据结构!齐鲁工业大学(山东省科学院)计算机考研...
齐鲁工业大学位于山东省济南市,是一所双非大学.齐鲁工业大学计算机学科评估没有,软件工程学科评估也没有,计算机实力不强.2017年,齐鲁工业大学和山东省科学院合并,因此校名后面有了括号. 齐鲁工业大学前 ...
- 【调剂】齐鲁工业大学(山东省科学院)2020年硕士研究生预调剂通知
点击文末的阅读原文或者公众号界面左下角的调剂信息或者公众号回复"调剂"是计算机/软件等专业的所有调剂信息集合,会一直更新的. 2020年我校硕士研究生招生拟接收部分调剂考生,有调剂 ...
- 计算机学院新增电子信息!齐鲁工业大学
齐鲁工业大学是一所双非大学,位于山东省济南市.齐鲁工业大学计算机学科评估没有,软件工程学科评估也没有,计算机实力在双非中并不强.今年齐鲁工业大学计算机考研有些变化.我们先看看去年的招生目录: 齐鲁工业 ...
- 齐鲁工业大学计算机考研资料汇总
齐鲁工业大学研招网 http://yjszs.qlu.edu.cn/ 齐鲁工业大学(山东省科学院)(Qilu University of Technology),位于山东省济南市,是山东省重点建设的应 ...
- 2023齐鲁工业大学计算机考研信息汇总
齐鲁工业大学研招网 http://yjszs.qlu.edu.cn/ 齐鲁工业大学(山东省科学院)(Qilu University of Technology),位于山东省济南市,是山东省重点建设的应 ...
- 齐鲁工业大学计算机科学与技术学院院长,齐鲁工业大学校友会计算机科学与技术学院校友会分会成立...
为广泛联络省内外校友,搭建校友与母校交流沟通的平台,增进校友与母院之间的联系.2020年12月26日,齐鲁工业大学计算机科学与技术学院在图书馆五楼报告厅举行校友会分会成立大会.学校(科学院)副校(院) ...
- 齐鲁工业大学计算机读研,齐鲁工业大学考研难吗
齐鲁工业大学考研难吗? 1.齐鲁工业大学考研难度算是比较容易.不在大学考研难度排名前100名单之内. 2.考研究生难易程度还是看招生院校的地域.名气.排名等因素,生源不同,竞争力度也不同.发达地区特别 ...
最新文章
- oracle取_后的数字,聊聊四种Oracle数字取整函数
- Shell脚本攻略02-玩转变量与环境变量
- 设计模式之十一:抽象工厂模式(Abstract Factory)
- vue之自行实现派发与广播-dispatch与broadcast
- About static contructor API changes in cocos2d-...
- Freeswitch+Sip.js实现软电话功能
- matlab求向量的模,MATLAB向量的模
- requests.exceptions.ConnectionError: HTTPConnectionPool(host=‘****, port=80): Max retries exceeded w
- CSS 函数摘抄笔记1207
- 如何将已有项目导入SVN
- 好一个“Exchange20003”
- 宣化上人:诸病从何来?
- oracle rac定时清理归档日志,Rman 定时删除归档日志
- FoodDelivered-Robot---送餐机器人(六)模块驱动代码---IO采集部分
- 《苏菲的世界》读书笔记之一:自然派哲学家
- RxJava学习 - 11. Switching, Throttling, Windowing, and Buffering
- POSTGRESQL 用户怎么乱糟糟,出自其他DB的评论, 与SCHEMA 移魂大法
- 计算机组成原理——微程序实验
- Oracle动态采样分析
- Java中Math函数的使用