[POI2011] SEJ-Strongbox(數論)

題目

描述

Byteasar is a famous safe-cracker, who renounced his criminal activity and got into testing and certifying anti-burglary devices.
He has just received a new kind of strongbox for tests: a combinatorial safe.
A combinatorial safe is something different from a combination safe, even though it is opened with a rotary dial.
The dial can be set in n different positions, numbered from 0 to n1 .
Setting the dial in some of these positions opens the safe, while in others it does not.
And here is the combinatorial property, from which the name comes from:
if x and y are opening positions, then so is (x+y) mod n too; note that is holds for x=y as well.
Byteasar tried k different positions of the dial: m1,m2,,mk .
The positions m1,m2,,mk1 did not open the safe,only the last position mk did.
Byteasar is already tired from checking these k positions and has thus absolutely no intention of trying the remaining ones.
He would like to know however, based on what he already knows about the positions he tried, what is the maximum possible number of positions that open the safe.
Help him by writing an appropriate program!

輸入

The first line of the standard input gives two integers n and k , separated by a single space, 1k250 000 , kn1014 .
The second line holds kk different integers, also separated by single spaces, m1,m2,,mk , 0mi<n .
You can assume that the input data correspond to a certain combinatorial safe that complies with the description above.
In tests worth approximately 70% of the points it holds that k1000 .
In some of those tests, worth approximately 20% of the points, the following conditions hold in addition: n108 and k100 .

輸出

Your program should print out to the first and only line of the standard output a single integer: the maximum number of the dial’s positions that can open the safe.

輸入樣例

42 5
28 31 10 38 24

輸出樣例

14

解題思路

首先說明兩個結論:

結論1:如果x 是密碼,那麼gcd(x,n) 也是密碼。
證明:
d=gcd(x,n)
由題意,因x 是密碼,故 2x%n,3x%n,,kx%n 均是密碼
又由貝祖定理推論(不定方程ax+by=c 有整數解的充要條件是gcd(a,b)|c ),xk+nc=d 一定有整數解(未知數是kc ),那麼 kZ 使得kxd(mod n) ,故d 也是密碼

結論2:如果x,y 是密碼,那麼gcd(x,y) 也是密碼。
證明:
d=gcd(x,y)
由題意,因x,y 是密碼,易知 (px+qy)%n 也是密碼(p,q0
又由貝祖定理推論,xp+yq=d 一定有整數解(未知數是pq ),那麼  p,qZ 使得 px+qyd(mod n) ,故d 也是密碼

再看看這道題,設 x,y 均爲密碼且x 是所有密碼中最小的,若xy ,則 gcd(x,y)<xgcd(x,y) 是密碼(結論2),與假設矛盾,故 x|y 。因此,這組密碼爲 x,2x,3x,,kx (kx<n) ————①
d=gcd(mk,n) ,由於mk 是密碼,根據結論1,d 也是密碼,又由①得:x|d (仍設x 是所有密碼中最小的那個)

但是這道題給了一些限制條件:
1. 要求最多有多少密碼,故我們希望x 儘量的小,密碼數量爲n/x
2. 給出了k1 個不是密碼的數字,故 x 不能整除 m1,m2,,mk1

綜上所述,這道題的實現方法是:在根號的時間裏暴力枚舉處理出 gcd(mk,n) 的所有因數,去除能整除 m1,m2,,mk1 中任意一個的數,設剩下的數中最小的爲x ,則答案就是 n/x


Code

(洛谷上卡時過了……應該可以優化一下算法)

#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;

typedef long long LL;

LL n, k, a[250005], d, q[250005], mn;

LL gcd(LL a, LL b){
    if(a < b)   a ^= b, b ^= a, a ^= b;
    return b == 0 ? a : gcd(b, a % b);
}

int main(){
    scanf("%lld%lld", &n, &k);
    for(int i = 1; i <= k; i++) scanf("%lld", &a[i]);
    d = gcd(a[k], n);
    for(LL i = 1; i <= sqrt(d); i++)
        if(d % i == 0){
            q[++q[0]] = i;
            if(i * i != d)
                q[++q[0]] = d / i;
        }
    sort(q+1, q+q[0]+1);
    for(int i = 1; i < k; i++)
        for(int j = 1; j <= q[0]; j++)
            if(q[j] && a[i] % q[j] == 0)
                q[j] = 0;
    for(mn = 1; mn <= q[0]; mn++)
        if(q[mn])   break;
    printf("%lld\n", n / q[mn]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章