2021-10-05~04数学小练

Goldbach’s Conjecture

线性筛出所有范围内的质数,暴力枚举就行了。
(一开始 c i n cin cin 挂了,所以直接上了快读,实际上 s c a n f scanf scanf 就行了)
线性筛 ▼ \blacktriangledown

void pre(){
    int n=N-10;
    for(int i=2;i<=n;++i){
        if(!v[i]) p[++m]=v[i]=i;
        for(int j=1;j<=m;++j){
            if(p[j]>v[i] || p[j]>n/i) break;
            v[p[j]*i]=p[j];
        }
    }
}

主程序 ▼ \blacktriangledown

    read(n);
    while(n){
        for(int j=2;p[j]<=n;++j){
            if(v[n-p[j]]==n-p[j]){
                prt(n),printf(" = "),prt(p[j]),printf(" + "),prt(n-p[j]),puts("");
                break;
            }
        }
        read(n);
    }

Prime Distance/质数距离

2 31 2^{31} 231 的范围显然不能线性筛出所有质数,但我们可以根据线性筛的思想,求出范围内的所有数的最小质因子,复杂度 O ( R ) O(\sqrt R) O(R ) ,又加上 L − R L-R LR的值很小 ,对于筛出来的每一个质数 p p p,把 [ L , R ] [L,R] [L,R] 中能被 p p p 整除的数标记为合数。剩下没被标记的数既是质数,时间复杂度 O ( R l o g l o g R + ( R − L ) l o g l o g R ) O(\sqrt Rloglog\sqrt R+(R-L)loglogR) O(R loglogR +(RL)loglogR)

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100006, L = 1000006, M = 46340, INF = 0x7fffffff;
bool v[L];
vector<int> p, ans;
 
int main() {
    memset(v, 1, sizeof(v));
    for (int i = 2; i <= N; i++)
        if (v[i]) {
            p.push_back(i);
            for (int j = 2; j <= N / i; j++) v[i*j] = 0;
        }
    unsigned int l, r;
    while (cin >> l >> r) {
        memset(v, 1, sizeof(v));
        ans.clear();
        if (l == 1) v[0] = 0;
        for (unsigned int i = 0; i < p.size(); i++)
            for (unsigned int j = (l - 1) / p[i] + 1; j <= r / p[i]; j++)
                if (j > 1) v[p[i]*j-l] = 0;
        for (unsigned int i = l; i <= r; i++) 
            if (v[i-l]) ans.push_back(i);
        int minn = INF, maxx = 0, x1, y1, x2, y2;
        for (unsigned int i = 0; i + 1 < ans.size(); i++) {
            int num = ans[i+1] - ans[i];
            if (num < minn) {
                minn = num;
                x1 = ans[i];
                y1 = ans[i+1];
            }
            if (num > maxx) {
                maxx = num;
                x2 = ans[i];
                y2 = ans[i+1];
            }
        }
        if (!maxx) puts("There are no adjacent primes.");
        else printf("%d,%d are closest, %d,%d are most distant.\n", x1, y1, x2, y2);
    }
    return 0;
}

反素数 Antiprime

题目传送

樱花

先转化一下式子,通分 x + y x y = 1 n ! \frac{x+y}{xy}=\frac{1}{n!} xyx+y=n!1变形 x y − n ! ( x + y ) = 0 xy-n!(x+y)=0 xyn!(x+y)=0左右同时加上 ( n ! ) 2 (n!)^2 (n!)2 ( n ! ) 2 − n ! ( x + y ) + x y = ( n ! ) 2 (n!)^2-n!(x+y)+xy=(n!)^2 (n!)2n!(x+y)+xy=(n!)2 因式分解 ( x − n ! ) ( y − n ! ) = ( n ! ) 2 (x-n!)(y-n!)=(n!)^2 (xn!)(yn!)=(n!)2 a = x − n ! , b = y − n ! a=x-n! , b=y−n! a=xn!,b=yn! a b = ( n ! ) 2 ab=(n!)^2 ab=(n!)2
n ! = p 1 c 1 × p 2 c 2 × ⋯ × p k c k n!=p_{1}^{c_1}\times p_{2}^{c_2}\times\cdots\times p_{k}^{c_k} n!=p1c1×p2c2××pkck ( n ! ) 2 = p 1 2 c 1 × p 2 2 c 2 × ⋯ × p k 2 c k (n!)^2=p_{1}^{2c_1}\times p_{2}^{2c_2}\times\cdots\times p_{k}^{2c_k} (n!)2=p12c1×p22c2××pk2ck

所以只要计算 ( n ! ) 2 (n!)^2 (n!)2 的约数个数,即 ( 2 c 1 + 1 ) ( 2 c 2 + 1 ) ⋯ ( 2 c k + 1 ) (2c_1+1)(2c_2+1)\cdots(2c_k+1) (2c1+1)(2c2+1)(2ck+1)。关于 c i c_i ci 求法详见阶乘分解,这里给公式 c i = ∑ p k ≤ N ⌊ N p k ⌋ c_i=\sum_{p^{k}\leq{N}}\lfloor\frac{N}{p^{k}} \rfloor ci=pkNpkN

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
   T ch=getchar(),xx=1;x=0;
   while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
   while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
   x*=xx;
}
template<typename T>inline void prt(T x){
   if(x<0) putchar('-'),x=-x;
   if(x>9) prt(x/10);
   putchar(x%10|48);
}
#define int long long
#define N 1000010
const int MOD=1e9+7;
int v[N],p[N],m,ans;
void pre(int n){
   for(int i=2;i<=n;++i){
       if(!v[i]) p[++m]=i,v[i]=i;
       for(int j=1;j<=m;++j){
           if(p[j]>v[i] || p[j]>n/i) break;
           v[i*p[j]]=p[j];
       }
   }
}
signed main(){
   int n;
   read(n);
   pre(n);
   ans++;
   for(int i=1;i<=m;++i){
       int k=0,g=p[i];
       while(n>=g){
           k+=n/g;
           g*=p[i];
       }
       ans=(ans*(2*k+1))%MOD;
   }
   prt(ans);
   return 0;
}

方程的解

题目等价为将 x x x 个球放入 k k k 个篮子中 ,篮子非空,假设 x x x 个球有 x − 1 x-1 x1 个缝,要放入 k − 1 k-1 k1 个板子, 所以答案为 C n − 1 k − 1 \mathrm{C}_{n-1}^{k-1} Cn1k1 ,记得高精

#include<bits/stdc++.h>
using namespace std;
#define N 5000
const int mm=10;
struct A {
    int a[N],len;
    A(int x=0):a() {
        for (int i=x; i; i/=mm) a[++len]=i%mm;
        if (!len) len++;
    }
    void print() {
        for (int i=len; i>=1; i--) printf("%d",a[i]);
        printf("\n");
    }
};
A operator * (const A &a,const A &b) {
    A c;
    c.len=a.len+b.len;
    for (int i=1; i<=a.len; i++)
        for (int j=1; j<=b.len; j++) {
            c.a[i+j-1]+=a.a[i]*b.a[j];
            c.a[i+j]+=c.a[i+j-1]/mm;
            c.a[i+j-1]%=mm;
        }
    while (c.len>1&&!c.a[c.len]) c.len--;
    return c;
}
A operator / (const A &a,int k) {
    A c;
    c.len=a.len;
    int x=0;
    for (int i=a.len; i>=1; i--) {
        x=x*mm+a.a[i];
        c.a[i]=x/k;
        x%=k;
    }
    while (c.len>1&&!c.a[c.len]) c.len--;
    return c;
}
bool operator < (const A &a,const A &b) {
    if (a.len!=b.len) return a.len<b.len;
    for (int i=a.len; i>=1; i--)if (a.a[i]!=b.a[i]) return a.a[i]<b.a[i];
    return 0;
}
bool operator > (const A &a,const A &b) {
    return b<a;
}
int x,k;
int qpow(int x,int y,int p) {
    int ret=1;
    while(y) {
        if(y&1) ret=ret*x%p;
        x=x*x%p;
        y>>=1;
    }
    return ret;
}
int main() {
    scanf("%d%d",&k,&x);
    x=qpow(x%1000,x,1000);
    if(k>x || x==0) puts("0");
    else if(k==1 || k==x) puts("1");
    else {
        x--,k--;
        A ans;
        ans.a[1]=1;
        ans.len=1;
        for(int i=x-k+1;i<=x;++i){
            A s;
            int j=i;
            s.len=0;
            while(j){
                s.a[++s.len]=j%10;
                j/=10;
            }
            ans=ans*s;
        }
        for(int i=1;i<=k;++i) ans=ans/i;
        ans.print();
    

五指山

解同余方程 k d ≡ y − x ( m o d n ) kd \equiv {y-x} \pmod{n} kdyx(modn)

#include<bits/stdc++.h> 
using namespace std;
template<typename T>inline void read(T &x){
    T ch=getchar(),xx=1;x=0;
    while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    x*=xx;
}
template<typename T>inline void prt(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) prt(x/10);
    putchar(x%10|48);
}
#define ll long long
void exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){x=1;y=0;return ;}
    exgcd(b,a%b,x,y);
    int z=x;x=y;y=z-y*(a/b);
    return ;
}
ll gcd(ll a,ll b){
    return b==0 ? a : gcd(b,a%b);
}
ll T,n,d,a,b,x,y;
int main(){
    read(T);
    while(T--){
        read(n),read(d),read(a),read(b);
        b-=a;
        int k=gcd(d,n);
        int t=n/k;
        if(b%k){
            puts("Impossible");
        }
        else {
            exgcd(d,n,x,y);
            x*=(b/k);
            x=(x%t+t)%t;
            prt(x);
            puts("");
        }
    }
}

Xiao 9*大战朱最学

详见曹冲养猪

Matrix Power Series

先抛开矩阵不谈,题目即为如何在不用求和公式(不用除法)求等比数列前 k k k 项和。
假设 k k k 16 16 16 S 16 = a 1 + a 2 + ⋯ + a 16 = ( a 1 + ⋯ + a 8 ) + ( a 9 + ⋯ + a 16 ) = ( a 1 + ⋯ + a 8 ) × a 8 S_{16}=a^{1}+a^2 +\cdots +a^{16}=(a^1+\cdots+a^8)+(a^9+\cdots+a^{16})=(a^1+\cdots+a^8)\times a^8 S16=a1+a2++a16=(a1++a8)+(a9++a16)=(a1++a8)×a8,这样只要求 S 8 S_{8} S8 a 8 a^8 a8 同理 S 8 S_{8} S8 也可以这样得出这样就可以 递归 + 快速幂 在 O ( l o g N ) O(logN) O(logN) 的效率得出来,最后套上矩阵,在递归的时候注意 k k k 的奇偶性就行了。

#include<bits/stdc++.h> 
using namespace std;
template<typename T>inline void read(T &x){
    T ch=getchar(),xx=1;x=0;
    while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    x*=xx;
}
template<typename T>inline void prt(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) prt(x/10);
    putchar(x%10|48);
}
const int N=36;
struct M{int a[N][N];};
int n,k,m;
M add(M x,M y) {
    M c;
    for (int i=0;i<n;i++)
        for (int j=0;j<n;j++)
            c.a[i][j]=(x.a[i][j]+y.a[i][j])%m;
    return c;
}
M mul(M x,M y) {
    M c;
    memset(c.a,0,sizeof(c.a));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            for (int k = 0; k < n; k++)
                c.a[i][j] = (x.a[i][k] * y.a[k][j] % m + c.a[i][j]) % m;
    return c;
}
M ksm(M x,int k){
    M c;
    memset(c.a,0,sizeof(c.a));
    for(int i=0;i<n;++i) c.a[i][i]=1;
    while(k){
        if (k&1) c=mul(c,x);
        x=mul(x,x);
        k>>=1;
    }
    return c;
}
M get(M x,int k) {
    if(k==1) return x;
    M y=ksm(x,(k+1)>>1);
    M z=get(x,k>>1);
    return k&1 ? add(x,mul(add(x,y),z)):mul(add(ksm(x,0),y),z);
}
int main() {
    M x;
    read(n),read(k),read(m);
    for (int i=0;i<n;i++)
        for (int j=0;j<n;j++)
            read(x.a[i][j]);
    x = get(x,k);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            cout << x.a[i][j] << " ";
        cout << endl;
    }
    return 0;
}

石头游戏

详见注释

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,m,t,act,p;
char b[10][10],s[11];
int num(int i,int j){return (i-1)*m+j;}
void mul(LL f[65],LL a[65][65]){
    LL c[65];
    memset(c,0,sizeof(c));
    for(int i=0;i<p;i++)
        for(int j=0;j<p;j++)
            c[i]=c[i]+f[j]*a[j][i];
    memcpy(f,c,sizeof(c));
}
void selfmul(LL a[65][65],LL b[65][65]){
    LL c[65][65];
    memset(c,0,sizeof(c));
    for(int i=0;i<p;i++)
        for(int k=0;k<p;k++)
            if(a[i][k])
                for(int j=0;j<p;j++)
                    c[i][j]=c[i][j]+a[i][k]*b[k][j];
    memcpy(a,c,sizeof(c));
}
int a[10][10];//每个点的操作序号 
int c[10][10];//每个点对应操作的具体步骤 
LL f[65],d[65][65],state[65][65][65],ans;
int main(){
    scanf("%d%d%d%d",&n,&m,&t,&act);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        for(int j=1;j<=m;j++) a[i][j]=(s[j-1]^48)+1;//每个点的操作序号
    }
    for(int i=1;i<=act;i++) scanf("%s",b[i]);
    p=n*m+1;
    for(int k=1;k<=60;k++){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                int x=a[i][j],y=c[i][j];
                if(isdigit(b[x][y])){
                    state[k][0][num(i,j)]=b[x][y]-'0';/*添加*/
                    state[k][num(i,j)][num(i,j)]=1;/*继承*/}
                if(b[x][y]=='N' && i>1) state[k][num(i,j)][num(i-1,j)]=1;
                if(b[x][y]=='W' && j>1) state[k][num(i,j)][num(i,j-1)]=1;
                if(b[x][y]=='S' && i<n) state[k][num(i,j)][num(i+1,j)]=1;
                if(b[x][y]=='E' && j<m) state[k][num(i,j)][num(i,j+1)]=1;
                c[i][j]=(y+1)%strlen(b[x]);//操作循环 
            }
        state[k][0][0]=1;   
    }
    memcpy(d,state[1],sizeof(state[1]));//d为A的60次方
    for(int k=2;k<=60;k++) selfmul(d,state[k]);
    f[0]=1;
    int w=t/60;
    while(w){//矩阵快速幂  d的w次方
        if(w&1) mul(f,d);
        selfmul(d,d);
        w>>=1;
    }
    w=t%60;
    for(int i=1;i<=w;i++) mul(f,state[i]);
    for(int i=1;i<p;i++) ans=max(ans,f[i]);
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值