1. 程式人生 > >BZOJ2277: [Poi2011]Strongbox

BZOJ2277: [Poi2011]Strongbox

iostream 找到 using ide clu sse 數字 爆炸 規則

n<=10^14,0~n-1中有一些數是密碼,且滿足:a是密碼,b是密碼,那麽(a+b)%n也是密碼(a,b可相等),現小明試了m<=250000個數,前面都錯,最後一個對,問n個數中最多有多少密碼。

好端端的一道數論題變卡常題。。

根據那個規則,把最後猜到那個數字t帶進去,那麽t,2t,3t……都是密碼,然而是%n下,所以0,(t,n),2*(t,n),……,n-(t,n)都是密碼。

那假如有別的數字是密碼,那肯定也類似這樣構成一個等間隔的東西。所以目標是找到這個最小的間隔。

這個間隔應該能達到(t,n),也就是應該是(t,n)的因子,所以現在就可枚舉(t,n)的因子檢驗一下其他不滿足的位置會不會被搞到,也就是有沒有x|Ai即可。

然而因子個數*m爆炸了,於是花了一下午想有什麽其他算法。。然而這是對的,只需要卡一卡即可

因為10^14以內的數字最多只有17000多個因子,而對一個數Ai,其實檢驗(Ai,n)是否滿足不被x整除也是一樣的,因為Ai的其他因子在這個周期跳躍活動中沒有啥用。於是把m個數都對n取gcd,然後去個重,復雜度就變成因子個數^2+mlogn了!

哦。

技術分享圖片
 1 #include<cstring>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 //#include<assert.h>
 5 #include<algorithm>
 6
//#include<iostream> 7 using namespace std; 8 9 #define LL long long 10 #define maxn 250011 11 LL n; int m; LL a[maxn]; 12 LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;} 13 bool check(LL x) 14 { 15 for (int i=1;i<=m;i++) 16 if (a[i]%x==0) return 0; 17 return 1; 18 } 19 int main()
20 { 21 scanf("%lld%d\n",&n,&m); 22 for (int i=1;i<=m;i++) scanf("%lld",&a[i]),a[i]=gcd(a[i],n); 23 LL base=a[m]; sort(a+1,a+m); m=unique(a+1,a+m)-a-1; 24 LL ans; 25 for (int i=1;1ll*i*i<=base;i++) if (base%i==0) 26 { 27 if (check(i)) {ans=n/i; break;} 28 else if (check(base/i)) {ans=n/(base/i);} 29 } 30 printf("%lld\n",ans); 31 return 0; 32 }
View Code

BZOJ2277: [Poi2011]Strongbox