数学知识专题

问题 A: 阶乘分解

题目描述

给定整数N(1≤N≤10^6),试把阶乘N!分解质因数,按照算术基本定理的形式输出分解结果中的pi和ci即可。

 

输入

一个整数N。

 

输出

N! 分解质因数后的结果,共若干行,每行一对pi, ci,表示含有pi^ci项。按照pi从小到大的顺序输出。

 

样例输入

5

样例输出

2 3
3 1
5 1

打一个素数表(顺便把每个数的素因子push_back进vector),然后暴力2--n,放到vis数组里,最后扫一遍素数表输出

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int n,prim[maxn],cnt;
int vis[maxn];
vector<int> vec[maxn];
void init(){
    for(int i=2;i<maxn;i++)
    if(!vis[i]){
        prim[cnt++] = i;
        for(int j=i;j<maxn;j+=i)
            vis[j] = 1,vec[j].push_back(i);
    }
    memset(vis,0,sizeof(vis));
}
int main() {
    init();
    scanf("%d",&n);
    if(n==1)
        return 0*printf("2 0\n");
    for(int i=2;i<=n;i++){
        int ti = i;
        for(auto j:vec[i]){
            while(ti%j==0)
                vis[j]++,ti/=j;
        }
    }
    for(int i=0;i<cnt;i++)
        if(vis[prim[i]])
            printf("%d %d\n",prim[i],vis[prim[i]]);
 
    return 0;
}

 

 

 

反素数ant

 

问题 E: 余数之和

题目描述

给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值
其中k mod i表示k除以i的余数。
例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

输入

输入仅一行,包含两个整数n, k。
1<=n ,k<=10^9

输出

输出仅一行,即j(n, k)。

样例输入

5 3

样例输出

7

容易看出ans=\sum_{i=1}^{min(n,k)}(k)mod(i)=\sum_{i=1}^{min(n,k)}k-k/i*i=n*k-\sum_{i=1}^{min(n,k)}k/i*i
那么不好求的就是这个\sum_{i=1}^{min(n,k)}k/i*i

先看个简单的,\sum_{i=1}^{min(n,k)}k/i怎么求,解法肯定不能暴力(会超时),

那么设k/l==k/r(l,r为区间左右端点)

那么r=k/(k/l)

很明显这样就可以了

for(ll l=1,r;l<=k;l=r+1){
    r = k/(k/l);
    ans += (r-l+1)*(k/l);
}

现在回过头来看\sum_{i=1}^{min(n,k)}k/i*i,发现其实就是加了个权值,那么只要

for(ll l=1,r;l<=k;l=r+1){
    r = k/(k/l);
    ans += (r+l)(r-l+1)/2*(k/l);
}

但是这样会wa,因为并不一定会将整个区间加进去,所以

这是Ac代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll Get(ll n,ll k){
    ll ans = 0;
    ll cnt = min(k,n);
    for(ll l=1,r;l<=cnt;l=r+1){
        r = min(cnt,k/(k/l));
        ans += (r+l)*(r-l+1)/2*(k/l);
    }
    return n*k-ans;
}
int main() {
    cin>>n>>k;
    cout<<Get(n,k)<<endl;
    return 0;
}
 

G: 同余方程

 

求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。

输入只有一行,包含两个正整数 a, b,用一个空格隔开。

输出只有一行,包含一个正整数 x0,即最小正整数解。输入数据保证一定有解。

exgcd

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll& x,ll& y){
    if(b == 0){
        x = 1,y = 0;
        return a;
    }
    ll ans = exgcd(b, a%b, y, x);
    y -= x*(a/b);
    return ans;
}
int main(){
    ll a,b,x,y;
    scanf("%lld%lld",&a,&b);
    exgcd(a,b,x,y);
    printf("%lld\n",(x+b)%b);
    return 0;
}

 

 

问题 I: Fibonacci

In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
An alternative formula for the Fibonacci sequence is

Given an integer n, your goal is to compute the last 4 digits of Fn.

 

The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.

 

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

矩阵快速幂=-=

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
    int a[2][2];
    void zero(){
        a[1][1]=a[0][0]=a[0][1]=a[1][0]=0;
    }
    void one(){
        a[0][1]=a[1][0]=0;
        a[0][0]=a[1][1]=1;
    }
    void Fib(){
        a[1][1]=0;
        a[0][0]=a[0][1]=a[1][0]=1;
    }
};
node operator * (node a,node b){
    node c;
    c.zero();
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            for(int k=0;k<2;k++)
                c.a[i][j] = (c.a[i][j]+a.a[i][k]*b.a[k][j]%10000)%10000;
        }
    }
    return c;
}
node Pow(node A,int b){
    node Ans;
    Ans.one();
    while(b){
        if(b&1)
            Ans = Ans*A;
        A = A*A;
        b>>=1;
    }
    return Ans;
}
int main(){
    node P;
    P.Fib();
    int t;
    while(cin>>t && ~t){
        node Ans = Pow(P,t);
        cout<<Ans.a[0][1]<<endl;
    }
    return 0;
}

 

问题 K: 球形空间产生器

 

有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。

第一行是一个整数n(1<=N=10)。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。

有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。

给出两个定义:

1 球心:到球面上任意一点距离都相等的点。

2 距离:设两个n为空间上的点A, B的坐标为(a1, a2, …, an), (b1, b2, …, bn),则AB的距离定义为:dist = sqrt( (a1-b1)^2 + (a2-b2)^2 + … + (an-bn)^2 )

高斯消元,算是个板子吧,

假设圆心点为(x_{1},x_{2},x_{3},x_{4},*****,x_{n})

那么对于圆上两个点a_{i}(x_{i,1},x_{i,2},x_{i,3},x_{i,4},*****,x_{i,n}))和a_{j}(x_{j,1},x_{j,2},x_{j,3},x_{j,4},*****,x_{j,n}))来说

显然有

r^{2}=(x_{i,1}-x_{1})^{2}+(x_{i,2}-x_{2})^{2}+(x_{i,3}-x_{3})^{2}+++(x_{i,n}-x_{n})^{2}

r^{2}=(x_{j,1}-x_{1})^{2}+(x_{j,2}-x_{2})^{2}+(x_{j,3}-x_{3})^{2}+++(x_{j,n}-x_{n})^{2}

消掉r^{2}再展开得到

2*((x_{i,1}-x_{j,1})*x_{1}++(x_{i,n}-x_{j,n})*x_{n})=(x_{i,1}^{2}-x_{j,1}^{2})++(x_{i,n}^{2}-x_{j,n}^{2})

也就是一个方程组,然后高斯消元即可

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 20;
double a[maxn][maxn],point[maxn][maxn];
double o2(double x){return x*x;}
void gauss(int n,int m){
    for(int i=1;i<=n;i++){
        int ml = i;
        for(int j=i+1;j<=n;j++)///find the max in the a[i---n][i]
            if (abs(a[j][i])>abs(a[ml][i]))
                ml = j;
        if (ml!=i)///swap the a[min_line] and a[i]
            for(int j=1;j<=m;j++)
                swap(a[ml][j],a[i][j]);
        double t = a[i][i];
        for(int j=1;j<=m;j++)///unitized the a[i]
            a[i][j] /= t;
        for(int j=1;j<=n;j++)/// change the a[1---n] ( subtract the t*a[i] )
            if (j!=i&&a[j][i]!=0){
                double t = a[j][i];
                for(int k=1;k<=m;k++)/// subtract the t*a[i]
                    a[j][k] -= t*a[i][k];
            }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n+1;i++)
        for(int j=1;j<=n;j++)
            scanf("%lf",&point[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            a[i][j] = 2*(point[i][j]-point[i+1][j]),a[i][n+1] += o2(point[i][j])-o2(point[i+1][j]);
    gauss(n,n+1);
    for(int i=1;i<=n-1;i++)
        printf("%.3f ",a[i][n+1]);
    printf("%.3f\n",a[n][n+1]);
    return 0;
}

问题 M: 计算系数

给定一个多项式(by+ax)k,请求出多项式展开后xn * ym 项的系数。

共一行,包含5 个整数,分别为 a ,b ,k ,n ,m,每两个整数之间用一个空格隔开。0≤k≤1000, 0≤n,m≤k 且 n+m=k, 0≤a,b≤100,000

输出共1 行,包含一个整数,表示所求的系数,这个系数可能很大,输出对10007 取模后的结果。

排列组合+逆元

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 10007,maxn = 1e3+7;
ll Fu[maxn],inv[maxn];
ll Pow(ll a,ll b){
    a %= p;
    ll ans = 1;
    while(b){
        if(b&1)
            ans = ans*a%p;
        a = a*a%p;
        b>>=1;
    }
    return ans;
}
void init(){
    Fu[0] = 1;
    for(int i=1;i<maxn;i++)
        Fu[i] = Fu[i-1]*i%p;
    inv[maxn-1] = Pow(Fu[maxn-1],p-2);
    for(int i=maxn-2;~i;i--)
        inv[i] = inv[i+1]*(i+1)%p;
}
ll C(ll n,ll m){
    return Fu[n]*inv[m]%p*inv[n-m]%p;
}
int main(){
    init();
    ll a,b,k,n,m;///(b*y+a*x)^k
    cin>>a>>b>>k>>n>>m;
    /// C(k,m)*b^m* a^k-m * y^m*x^k-m
    cout<<(C(k,m)*Pow(b,m)%p*Pow(a,n)%p)<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值