【BZOJ 4253】密码箱加强版

首先无视掉这题题面,您就全当机房的神犇在D蒟蒻我好了。
进入正题,首先这题的弱化版还是蛮好想的。设:

n=pk11pk22...pknn

对于 x2=1(modn) ,一定有
x2=1(modpk11)
x2=1(modpk22)

xn=1(modpknn)
而对于 x2=1(modpkkk) :
pk!=2 时, x 有以下取值
x=pkkk1(modpkkk) x=1(modpkkk)
pk=2 时, x 有另外两个取值(注意特判下 kk=1 的情况)
x=pkk1k1(modpkkk) x=pkk1k+1(modpkkk)
于是我们穷举 x 对于每个因子的取值,中国剩余定理合并即可。
但是。。。。
这题的n显然比较大,普通的 n 筛质因子已经满足不了需求,于是我学习了可以 n 筛质因子的pollard rho和配合使用的rabin miller算法。想要学习的可以百度一下或者看一下算导,讲的都听明白的,代码的话不嫌丑的话可以看一看我的。code:

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#define s 20
using namespace std;
long long n,x,y;
long long prime[51],tot,b[51],ret[51];
long long ansi[320001],totans;
long long mult(long long a,long long b,long long p)
{
    long long t;
    if (b==0) return 0;
    if (b==1) return a;
    t=mult(a,b/2,p);
    if (b%2==0) return (t+t)%p;
    else return ((t+t)%p+a)%p;
}
long long power(long long a,long long b,long long p)
{
    long long temp;
    if (b==0) return 1;
    if (b==1) return a;
    temp=power(a,b/2,p);
    if (b%2==0) return mult(temp,temp,p);
    else return mult(a,mult(temp,temp,p),p);
}
bool check(long long a,long long n,long long x,long long t)
{
     long long i,ret=power(a,x,n);
     long long last=ret;
     for (i=1;i<=t;++i)
       {
         ret=mult(ret,ret,n);
         if (ret==1&&last!=1&&last!=n-1) return false;
         last=ret;
       }
    if (ret!=1) return false;
    else return true;
}
bool is_prime(long long n)
{
    long long a,i,x,t=0;
    if (n<2) return false;
    if (n==2) return true;
    if (!(n&1)) return false;
    x=n-1;
    if (!(x&1)) {x>>=1; t++;}
    for (i=1;i<=s;++i)
      {
        a=rand()%(n-2)+2;
        if (!check(a,n,x,t)) return false;
      }
    return true;
}
long long _abs(long long x)
{
    if (x>0) return x;
    else return -x; 
}
long long gcd(long long a,long long b)
{
    if (a%b==0) return b;
    else return gcd(b,a%b);
}
long long pollard_rho(long long p)
{
    long long y,d,k,i,x,x0,c;
    c=(long long)(long long)(rand()*(long long)rand())%p;
    y=x=(long long)((long long)rand()*(long long)rand())%p;
    k=2; i=1;
    while (true)
      {
        i++;
        x=(mult(x,x,p)+c)%p;
        d=gcd(_abs(y-x),p);
        if (d!=1) return d;
        if (i==k)
          {y=x; k<<=1;}
      }
}
void make_list(long long n)
{
    long long i;
    long long x,minn;
    bool f,d;
    f=is_prime(n);
    if (f) 
      {
        d=false;
        for (i=1;i<=tot;++i)
          if (prime[i]%n==0)
            {prime[i]*=n; d=true;}
        if (!d) prime[++tot]=n;   
      }
    else
      {
        minn=pollard_rho(n);
        while (minn==n) minn=pollard_rho(n);
        make_list(minn);
        make_list(n/minn);
      }
}
void exgcd(long long a,long long b,long long p)
{
    long long t;
    if (a%b==0)
      {
        x=0;
        y=1;
      }
    else
      {
        exgcd(b,a%b,p);
        t=x%p;
        x=y%p;
        y=(t-mult((a/b),y,p)+p)%p;
      }
}
void make_ret()
{
    long long i,now,t;
    for (i=1;i<=tot;++i)
      {
        now=n/prime[i];
        now=now%prime[i];
        exgcd(now,prime[i],prime[i]); 
        x=(x%prime[i]+prime[i])%prime[i];
        t=n/prime[i];
        ret[i]=mult(x,t,n);  
      }
}
void solve()
{
    long long i,now,ans=0,t;
    for (i=1;i<=tot;++i)
      {
        x=mult(ret[i],b[i],n); 
        ans=(ans+x)%n;  
      }
    ansi[++totans]=ans;
}
void work(long long i)
{
    if (i==tot+1)
      {
        solve();
        return;
      }
    if (prime[i]==2)
      {b[i]=1; work(i+1);}
    else
      {
        b[i]=prime[i]-1; work(i+1);
        b[i]=1; work(i+1);
        if (prime[i]%2==0&&prime[i]>4)
          {
            b[i]=prime[i]/2+1;
            work(i+1);
            b[i]=prime[i]/2-1;
            work(i+1);
          }
      }
}
int main()
{
    long long i,size;
    scanf("%lld",&n);
    if (n==1) printf("None\n");
    else
      {
        make_list(n);
        make_ret();
        work(1);
        sort(ansi+1,ansi+totans+1);
        size=unique(ansi+1,ansi+totans+1)-ansi-1;
        for (i=1;i<=size-1;++i)
          printf("%lld ",ansi[i]);
        printf("%lld\n",ansi[size]);
      }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值