zoukankan      html  css  js  c++  java
  • [poi2011]bzoj 2277 —— strongbox·[洛谷3518]

    ·问题描述·

      有一个密码箱,0到n-1中的某些数是它的密码。且满足:如果a和b都是它的密码,那么(a+b)%n也是它的密码。某人试了k次密码,前k-1次都失败了,最后一次成功。

      问:该密码箱最多有多少个密码?

    ·输入格式·

      输入第一行两个整数分别表示n,k。

      第二行为k个用空格隔开的非负整数,表示每次试的密码。(数据保证存在合法解)

    ·输出格式·

      输出一行一个数,表示结果。

    ·输入样例·

    42 5

    28 31 10 38 24

    ·输出样例·

    14

    ·数据范围·

    对于100%的数据:1<=k<=250000,k<=n<=10^14。

    Solution:

      本题考察数学。由题意可知,若x为密码则(x+x)%n为密码,则p*x%n(0<p<n)也为密码。而对于p*x%n=q,等价于p*x-n*c=q。

      由引理:a*x+b*y=c(均为整数),有整数解的充要条件是gcd(a,b)|c。证明很容易:不妨设a=p*gcd(a,b),b=q*gcd(a,b) --> a*x+b*y=(p+q)*gcd(a,b)=c,显然要有整数解,则gcd(a,b)|c。

      回到本题的条件:p*x-n*c=q。有解则必定满足gcd(x,n)|q,所以必定有p*x-n*c=gcd(x,n)成立,等价于p*x%n=gcd(x,n),则gcd(x,n)一定为一个密码。类似的,对于不同的密码x和y,存在(p*x+q*y)%n为密码,由引理必定存在p*x+q*y=gcd(x,y),与单个x是密码同理gcd(x,y)一定是密码。

      而要使得密码最多,由x是密码则p*x%n(0<p<n)为密码可知,当x为最小时,密码最多有n/x个。

      具体实现时,我们先求出a[k]=gcd(a[k],n),再使a[i]=gcd(a[i],a[k]),然后从新的a[k]中删去所有是a[i]因子的因子,最后输出答案就是n除以没被删的最小的因子。

    代码:

     1 /*数学一本通上的例题——by 520*/
     2 #include<bits/stdc++.h>
     3 #define il inline
     4 #define ll long long
     5 using namespace std;
     6 ll n,k,tot,a[250005],q[250000],p[250000],cnt=1;
     7 il ll gi(){
     8     ll a=0;char x=getchar();bool f=0;
     9     while((x<'0'||x>'9')&&x!='-')x=getchar();
    10     if(x=='-')x=getchar(),f=1;
    11     while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    12     return f?-a:a;
    13 }
    14 il ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    15 int main()
    16 {
    17     freopen("strongbox.in","r",stdin);
    18     freopen("strongbox.out","w",stdout);
    19     n=gi(),k=gi();
    20     for(int i=1;i<=k;i++)a[i]=gi();
    21     a[k]=gcd(a[k],n);
    22     for(int i=1;i<k;i++)a[i]=gcd(a[k],a[i]);
    23     for(ll i=1;i*i<=a[k];i++)
    24         if(a[k]%i==0){
    25             q[++tot]=i;
    26             if(i*i!=a[k])q[++tot]=a[k]/i;
    27         }
    28     sort(q+1,q+tot+1);
    29     for(int i=1;i<k;i++)p[lower_bound(q+1,q+tot+1,a[i])-q]=1;
    30     for(int i=1;i<=tot;i++)
    31         if(p[i])
    32             for(int j=1;j<i;j++)
    33                 if(q[i]%q[j]==0)p[j]=1;
    34     while(p[cnt])cnt++;
    35     cout<<n/q[cnt];
    36     return 0;
    37 }
  • 相关阅读:
    C#中提供的精准测试程序运行时间的类Stopwatch
    [转]SQLite数据库扫盲
    [转]c# 使用ChartDirector绘图的一些个人体会
    [转]SQLite内存数据库
    SQL Server 各种查询语句执行返回结果
    [转]浅谈 BigInteger
    [转]SQLite数据库连接方式
    ASP.NET 3.5 开发大全DOC版
    好像昨天不见了100块钱。
    热烈庆祝本人昨天终于申请得了google ad
  • 原文地址:https://www.cnblogs.com/five20/p/8414577.html
Copyright © 2011-2022 走看看