自学内容网 自学内容网

C++知识点总结(56):数学专题

一、进制转换类

1. 模板

1.1 十转 x x x

while(n){
    num[++idx]=num2digit(x%i);
    x/=i;
}

1.2 x x x 转十

for(int i=s.size()-1;i>=0;i--){
    if(isdigt(s[i]))num=(num*10)+(s[i]-'0');
    else num=(num*10)+(10+s[i]-'A');
}

2. 例题

给定一个数 n n n 1 ≤ n ≤ 1 0 18 1\le n\le10^{18} 1n1018),求 2 ∼ 16 2\sim16 216 进制下该数是否为一个上升数(每位都满足 a i ≤ a i − 1 a_i\le a_{i-1} aiai1)。输出若干行,每行两个空格隔开的数,第一个数是对应进制,第二个数是对应进制下的上升数。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
signed main(){
    cin>>n;
    for(int i=2;i<=16;i++){//遍历每个进制
        int num[55]={},idx=0,flag=0,x=n;
        //计算i进制下的n,存储到num[]中
        while(x){
            num[++idx]=x%i;
            x/=i;
        }
        //判断是否为上升数
        for(int i=idx-1;i>=1;i--)
            if(num[i]<num[i+1]){
                flag=1;
                break;
            }
        if(flag)continue;
        //按要求输出
        cout<<i<<" ";
        for(int i=idx;i>=1;i--)
            if(num[i]<10)cout<<num[i];
            else cout<<(char)('A'+(num[i]-10));
        cout<<endl;
    }
    return 0;
}

二、公式推导类

1. 一元二次方程解

已知:
a x 2 + b x + c = 0 ax^2+bx+c=0 ax2+bx+c=0
则:
x = − b ± b 2 − 4 a c 2 a x = \frac{-b ± \sqrt{b^2 - 4ac}}{2a} x=2ab±b24ac
推导过程:

等式两边都 ÷ a \div a ÷a,得:
x 2 + b a x + c a = 0 x^2+\frac{b}{a}x+\frac{c}{a}=0 x2+abx+ac=0
移项,得:
x 2 + b a x = - c a x^2+\frac{b}{a}x=-\frac{c}{a} x2+abx=ac
方程两边都加上一次项系数 b a \frac{b}{a} ab 的一半的平方,即方程两边都加上 b 2 4 a 2 \frac{b^2}{4a^2} 4a2b2,(配方)得
x 2 + b a x + b 2 4 a 2 = b 2 4 a 2 - c a x^2+\frac{b}{a}x+\frac{b^2}{4a^2}=\frac{b^2}{4a^2}-\frac{c}{a} x2+abx+4a2b2=4a2b2ac
( x + b 2 a ) 2 = b 2 − 4 a c 4 a 2 x + b 2 a = ± b 2 − 4 a c 2 a x = − b ± b 2 − 4 a c 2 a (x+\frac{b}{2a})^2=\frac{b^2-4ac}{4a^2} \\ x+\frac{b}{2a}=±\frac{ \sqrt{b^2-4ac} }{2a} \\ x=\frac{-b±\sqrt{b^2-4ac}}{2a} (x+2ab)2=4a2b24acx+2ab=±2ab24ac x=2ab±b24ac

2. 例题

2.1 【模板】怪物同笼

n n n 组数据,给出第 1 1 1 种怪物有 a a a 个头 b b b 条腿,第 2 2 2 种怪物有 c c c 个头 d d d 条腿。所有怪物加起来有 e e e 个头 f f f 条腿。

思路:我们可以得出如下方程组( x x x 为怪物 1 1 1 的数量, y y y 为怪物 2 2 2 的数量):
{ a x + c y = e b x + d y = f \begin{cases} ax+cy=e \\ bx+dy=f \\ \end{cases} {ax+cy=ebx+dy=f
因此我们就推导得出 x x x 的求解公式:
a d x + c d y − b c x + c d y ( a d − b c ) x = d e − c f x = d e − c f a d − b c adx+cdy-bcx+cdy \\ (ad-bc)x=de-cf \\ x=\frac{de-cf}{ad-bc} adx+cdybcx+cdy(adbc)x=decfx=adbcdecf
以及 y y y 的求解公式:
a b x + a d y − a b x + b c y ( a d − b c ) y = a f − b e y = a f − b e a d − b c abx+ady-abx+bcy \\ (ad-bc)y=af-be\\ y=\frac{af-be}{ad-bc} abx+adyabx+bcy(adbc)y=afbey=adbcafbe

AC \text{AC} AC 代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,a,b,c,d,e,f;
signed main(){
    cin>>t;
    while(t--){
        cin>>a>>b>>c>>d>>e>>f;
        int g=d*e-c*f;
        int h=a*d-b*c;
        int i=a*f-b*e;
        int j=a*d-b*c;
        if(g%h!=0||i%j!=0||g/h<0||i/j<0){
            printf("No Solution\n");
            continue;
        }
        printf("%d %d\n",(d*e-c*f)/(a*d-b*c),(a*f-b*e)/(a*d-b*c));
    }
    return 0;
}

2.2 K K K 的倍数

给定一个长度为 n n n 的序列 a a a,求 a i − a j m o d    k = 0 a_i-a_j \mod k=0 aiajmodk=0 的个数( 1 ≤ i < j ≤ n 1\le i<j \le n 1i<jn)。

暴力枚举( “ “ 差缀和 ” ” ):

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,cnt;
int a[200010];
int c[200010];
int s[200010];
signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(i>=2){
            c[i]=a[i]-a[i-1];
            s[i]=s[i-1]+c[i];
        }
    }
    for(int l=2;l<=n;l++)
        for(int r=l;r<=n;r++)
            if((s[r]-s[l-1])%k==0)
                cnt++;
    cout<<cnt;
    return 0;
}

优化(同余思想):

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int MAXK=1e5+8;
int n,k,ans;
int cnt[MAXK];//存储j之前mod k=0,1,2,...,k-1的数分别有几个
signed main(){
    cin>>n>>k;
    for(int j=1,aj;j<=n;j++){
        cin>>aj;
        ans+=cnt[aj%k]++;
    }
    cout<<ans;
    return 0;
}

三、枚举

例题

1. 二次方程

s ( n ) s(n) s(n) 为正整数 n n n 的数码和,给出 a , b , c a,b,c a,b,c,求出所有满足 n = a × [ s ( n ) ] 2 + b × s ( n ) + c n=a\times[s(n)]^2+b\times s(n)+c n=a×[s(n)]2+b×s(n)+c的正整数 n n n

经典 G \text{G} G 法:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c;
int s(int n){
    int ret=0;
    while(n){
        ret+=n%10;
        n/=10;
    }
    return ret;
}
signed main(){
    cin>>a>>b>>c;
    for(int i=1;i<=1e7;i++)
        if(a*s(i)*s(i)+b*s(i)+c==i)
            cout<<i<<" ";
    return 0;
}

优化方法:
思想:反向枚举
n n n 的范围很大(不超过 9223372036854775807 9223372036854775807 9223372036854775807,我就粗略地说 1 0 20 10^{20} 1020 了)。但是 s ( n ) s(n) s(n) 最大也就 9 × 20 = 180 9\times 20=180 9×20=180。因此我们可以枚举 s ( n ) s(n) s(n),从 1 ∼ 180 1 \sim 180 1180,通过 n = a × [ s ( n ) ] 2 + b × s ( n ) + c n=a\times[s(n)]^2+b\times s(n)+c n=a×[s(n)]2+b×s(n)+c 算出 n n n,再通过 s n = S ( n ) sn = S(n) sn=S(n) 进行验算。 AC \text{AC} AC 代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c;
int s(int n){
    int ret=0;
    while(n){
        ret+=n%10;
        n/=10;
    }
    return ret;
}
signed main(){
    cin>>a>>b>>c;
    for(int sn=1;sn<=180;sn++){
        int n=a*sn*sn+b*sn+c;
        if(sn==s(n))cout<<n<<" ";
    }
    return 0;
}

2. 【模板】立方体体积

有一个立方体,它的长、宽、高是 a , b , c a,b,c a,b,c,立方体的体积等于长、宽、高的乘积。现在只知道立方体的体积等于 n n n,问立方体有多少种不同的可能的形状?长、宽、高顺序不同视作不同形状。

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,ans;
signed main(){
    cin>>n;
    for(int a=1;a*a*a<=n;a++){//不妨令a<=b<=c
        if(n%a!=0)continue;
        for(int b=a;b*b<=n/a;b++){
            int c=n/a/b;
            if(a*b*c==n){
                if(a==b&&b==c)ans++;
                else if(a==b||b==c)ans+=3;
                else ans+=6;
            }
        }
    }
    cout<<ans;
    return 0;
}

3. 街头篮球

教练想要从他带领的 n n n 名选手中选出一支篮球队。
每名选手的能力为整数,第 i i i 名选手的能力为 a i a_i ai。篮球队的队员数量必须是 3 3 3 人,一支队伍的总能力就是所有队员能力的总和。教练比较迷信,他的幸运数字是 m m m,所以他要求队伍的总能力必须是 m m m 的倍数。请帮他算一下,符合这个要求的队伍组合有多少?

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,ans;
int cnt[1005];
int cal(int x,int y,int z){
    if(x==y&&y==z)
        return 1ll*cnt[x]*(cnt[x]-1)*(cnt[x]-2)/6;
    if(x==y)
        return 1ll*cnt[x]*(cnt[x]-1)/2*cnt[z];
    if(y==z)
        return 1ll*cnt[x]*cnt[y]*(cnt[y]-1)/2;
    return 1ll*cnt[x]*cnt[y]*cnt[z];
}
signed main(){
    cin>>n>>m;
    for(int i=1,a;i<=n;i++){
        cin>>a;
        cnt[a%m]++;
    }
    for(int i=0;i<m;i++)
        for(int j=i;j<m;j++){
            int k=(2*m-i-j)%m;
            if(j<=k)ans+=cal(i,j,k);
        }
    cout<<ans;
    return 0;
}

原文地址:https://blog.csdn.net/joe_g12345/article/details/143648606

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!