ACM训练周末总结—11月26日

         这个周结束数论2专题,学习了好多知识点,先整理下题目,然后将知识点最后集中一下。

         V题:给出n,m求(1!+2!+3!+...n!)%m,虽然题目很大(10^100),但是已知(a*b)%m=(a%m*b%m)%m,而且当n>m时,n!%m==0,所以计算量也就没那么可怕。注意n的输入用字符转换就行了。(水题)

        H题:(水题)就是快速幂求几个数次方的和。

        I题:给出两个数L,R,求L<=x<=R,区间内两素数距离最长,和最短的两对。

        这是到好题,因为数据范围很大,不能够暴力达标预处理。   因为区间长度不超过10^6,所以先筛出,1到10^6之间的素数,然后利用线性筛素数的原理,确定题目中L和R的位置,利用一个10^6的数组做映射,筛出L到R之间所有的合数,同时将相应的位置映射回0到10^6的数组最后统计出区间内的素数,最后暴力找就行了,反正10^6之间素数也不是太多。

void solve()//映射,筛选处理
{
memset(notprime, false, sizeof(notprime));//记录映射回来的合数标记
if (L < 2) L = 2;
for (int i = 1; i <= cnt; i++)
{
if (prime[i] > R) break;
int p;
if (L % prime[i] == 0) p = L / prime[i];//确定给素数的倍数映射位置
else p = L / prime[i] + 1;
if (p == 1) p = 2;
while (p * prime[i] >= L && p * prime[i] <= R && (ll)prime[i] * prime[i] <= (ll)R)
{
notprime[p * prime[i] - L] = true;//映射处理
p++;
}
}
tot = 0;
for (int i = 0; i <= R - L; i++)
{
if (notprime[i] == false)
ans[++tot] = i + L;//将素数记录下来
}
}

这是道好题,把线性筛素数最大的发挥。。

       F题:就是判素数,要利用随机算法判断   Miller_Rabin算法判素数    Pollard_rho算法大数因数分解。

粘下模版吧,虽然有误差,s足够大,判错几率很小。就是利用欧拉定理带入随机数来测试。

这是一位大佬的板子。

//****************************************************************
// Miller_Rabin 算法进行素数测试
//速度快,而且可以判断 <2^63的数
//****************************************************************
const int S=20;//随机算法判定次数,S越大,判错概率越小
//计算 (a*b)%c.   a,b都是long long的数,直接相乘可能溢出的
//  a,b,c <2^63
long long mult_mod(long long a,long long b,long long c)
{
    a%=c;
    b%=c;
    long long ret=0;
    while(b)
    {
        if(b&1){ret+=a;ret%=c;}
        a<<=1;
        if(a>=c)a%=c;
        b>>=1;
    }
    return ret;
}
//计算  x^n %c
long long pow_mod(long long x,long long n,long long mod)//x^n%c
{
    if(n==1)return x%mod;
    x%=mod;
    long long tmp=x;
    long long ret=1;
    while(n)
    {
        if(n&1) ret=mult_mod(ret,tmp,mod);
        tmp=mult_mod(tmp,tmp,mod);
        n>>=1;
    }
    return ret;
}
//以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数
//一定是合数返回true,不一定返回false
bool check(long long a,long long n,long long x,long long t)
{
    long long ret=pow_mod(a,x,n);
    long long last=ret;
    for(int i=1;i<=t;i++)
    {
        ret=mult_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1) return true;//合数
        last=ret;
    }
    if(ret!=1) return true;
    return false;
}
// Miller_Rabin()算法素数判定
//是素数返回true.(可能是伪素数,但概率极小)
//合数返回false;
bool Miller_Rabin(long long n)
{
    if(n<2)return false;
    if(n==2)return true;
    if((n&1)==0) return false;//偶数
    long long x=n-1;
    long long t=0;
    while((x&1)==0){x>>=1;t++;}
    for(int i=0;i<S;i++)
    {
        long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件
        if(check(a,n,x,t))
            return false;//合数
    }
    return true;
}
//************************************************
//pollard_rho 算法进行质因数分解
//************************************************
long long factor[100];//质因数分解结果(刚返回时是无序的)
int tol;//质因数的个数。数组小标从0开始


long long gcd(long long a,long long b)
{
    if(a==0)return 1;
    if(a<0) return gcd(-a,b);
    while(b)
    {
        long long t=a%b;
        a=b;
        b=t;
    }
    return a;
}
long long Pollard_rho(long long x,long long c)
{
    long long i=1,k=2;
    long long x0=rand()%x;
    long long y=x0;
    while(1)
    {
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        long long d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k){y=x0;k+=k;}
    }
}
//对n进行素因子分解
void findfac(long long n)
{
    if(Miller_Rabin(n))//素数
    {
        factor[tol++]=n;
        if(ans>n) ans=n;
        return;
    }
    long long p=n;
    while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}

      Y题(Zombie's Treasure Chest):给出一个背包大小n,和两种宝石的体积s1,s2和价值v1,v2。求将宝石装入包中,价值最大。

      刚开始没意识到,结果wa了几发才意识到,因为不一定是先装性价比高的。

      其实是k1*s1+k2*s2<=n,k1*v1+k2*v2=ans,求最大的ans 。然后一个一个的暴力找。

if(v1*s2>=v2*s1)//此时性价比,一物品大于二物品
{
     ll cnt=min(s1-1,N/s2);//满足s1*v2<=s2*v1,此时显然有物品2的数量不会超过s1,(否则这s1个物品2的空间放物品1的价值为s2*v1更优)
     for(int i=0;i<=cnt;i++)
     {
            ll h=(N-(i*s2))/s1;
          ans=max(ans,i*v2+h*v1);
      }
}
else
{
     ll cnt=min(s2-1,N/s1);//同理
     for(int i=0;i<=cnt;i++)
     {
          ll h=(N-(i*s1))/s2;
          ans=max(ans,i*v1+h*v2);
     }
}

      B题:给出若干个单词,然后输入单词,判断有四种情况:

      1,有这个单词。输出正确。

      2,一个字母错。缺一个字母。多一个字母。

      3,完全错误。

其实就是暴力找。

int solve(char *str,char *ss)
{
    int len1,len2;
    len1=strlen(str);
    len2=strlen(ss);
    if(len1==len2)//判断是否只错一个
    {
        int cnt=0;
        for(int i=0;i<len1;i++)
        {
            if(str[i]!=ss[i])
            {
                cnt++;
                if(cnt>1) return 0;
            }
        }
        return 1;
    }
    else if(len1>len2)//是否多一个字
    {
        int cnt=0;
        for(int i=0;i<len1;i++)
        {
            if(str[i]==ss[cnt]) cnt++;
            if(cnt==len2) return 1;
        }
        return 0;
    }
    else if(len1<len2)//是否少一个
    {
        int cnt=0;
        for(int i=0;i<len2;i++)
        {
            if(str[cnt]==ss[i]) cnt++;
            if(cnt==len1) return 1;
        }
        return 0;
    }
}

       N题(OO’s Sequence):求每一个[L, R]区间中  j!=i a[i]对任意a[j]取余为0 的i的个数的总和。

这个题刚开始我一直在考虑区间dp,后来发现可以换一个方向考虑,不一定从区间入手算,可以考虑是该点在多少区间可以被当做元素+1,即找出 i 这个位置向左向右可以最多延展到哪可以符合条件(就是区间内其他因子不是它的因子),然后代入演算出的公式(r[i]-x+1)*(x-l[i]+1),加和。

而计算左右延展最长到哪有个小技巧。先从左到右依次对元素进行标记vis[ i ],表示 i 这个值最近在哪出现,在这之前爆搜判断这个值因子最近处,这样只找1到sqrt(a[i]),就可以了。

void  Left(int val,int t)
{
    l[t]=max(vis[val],vis[1]);
    for(int i=2;i*i<=val;i++)//这样就可以变成n*sqrt(n),就是提前做个标记的小操作。
    {
        if(val%i==0)
        {
            l[t]=max(l[t],vis[i]);
            l[t]=max(l[t],vis[val/i]);
        }
    }
}
void Right(int val,int t)//在倒着来一遍。
{
    r[t]=min(vis[val],vis[1]);
    for(int i=2;i*i<=val;i++)
    {
        if(val%i==0)
        {
            r[t]=min(r[t],vis[i]);
            r[t]=min(r[t],vis[val/i]);
        }
    }
}

         马上总结下一篇数论知识点总结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值