1. 程式人生 > >A Simple Stone Game HDU

A Simple Stone Game HDU

After he has learned how to play Nim game, Bob begins to try another stone game which seems much easier.  The game goes like this: one player starts the game with NN piles of stones. There is aiai stones on the iith pile. On one turn, the player can move exactly one stone from one pile to another pile. After one turn, if there exits a number x(x>1)x(x>1) such that for each pile bibi is the multiple of xx where bibi is the number of stone of the this pile now), the game will stop. Now you need to help Bob to calculate the minimum turns he need to stop this boring game. You can regard that 00 is the multiple of any positive number.

Input

The first line is the number of test cases. For each test case, the first line contains one positive number N(1≤N≤100000)N(1≤N≤100000), indicating the number of piles of stones.  The second line contains NN positive number, the iith number ai(1≤ai≤100000)ai(1≤ai≤100000)indicating the number of stones of the iith pile.  The sum of NN of all test cases is not exceed 5∗1055∗105. 

Output

For each test case, output a integer donating the answer as described above. If there exist a satisfied number xx initially, you just need to output 00. It's guaranteed that there exists at least one solution. 

Sample Input

2
5
1 2 3 4 5
2
5 7

Sample Output

2
1

題意就是給你N堆石頭 每次可以將一塊石頭從一堆移動到另一堆,求最小的移動次數使每一堆都是某個數 X的倍數

理解:每一堆都是X的倍數那麼石頭的總數必然是X的倍數,那麼就可以列舉石頭總數的質因子,求出符合條件的最小次數便可以

列舉質因子可以用尤拉篩打表預處理一下素數表,然後列舉素數,如果不能整除則跳過,由於答案必然不會很大所以不會超時。

接著關鍵在於怎麼判定該質因子滿足條件並且求出轉移次數。

這裡用了一個技巧,現將b[i]=a[i]%prime[j] 求出, 然後對b  sort一下 然後從最左邊l 和最右邊r 開始 令tt=min(prime[j]-b[r], b[l])

然後令b[l]-=tt , b[r]+=tt (就是將前面補到後面) 若左邊b[l]=0 則l右移 ,若右邊b[r] =prime[j] 則r 左移

然後求所有結果的最小值 程式碼如下 

#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int maxl=500000+10; bool check[maxl]; int prime[500005]; int a[100005]; int b[100005]; int tot=0; long long ans=0; long long Min; int Max=-1; int T; int N; int main() {     memset(check , 0 , sizeof(check));     for(int i = 2 ; i < maxl ; ++i)     {         if(!check[i])prime[tot++] = i;         for(int j = 0 ; j < tot ; j++)         {             if(i * prime[j] > maxl)break;             check[i * prime[j]] = 1;             if ( i % prime[j] == 0 )break;         }     }     scanf("%d",&T);     while(T--)     {         ans=0;         Max=-1;         scanf("%d",&N);         for(int i=1;i<=N;i++)         {             scanf("%d",&a[i]);             Max=max(Max,a[i]);             ans+=a[i];         }         Min=ans-Max;         for(int j=0;j<tot&&prime[j]<=ans;j++)         {             if(ans%prime[j]!=0)continue;             for(int k=1;k<=N;k++)             {                 b[k]=a[k]%prime[j];             }             sort(b+1,b+1+N);             long long l=1;             long long  r=N;             long long result=0;             while(l<r)             {                 int tt=min(b[l],prime[j]-b[r]);                 b[l]-=tt;                 b[r]+=tt;                 result+=tt;                 if(b[l]==0)l++;                 if(b[r]==prime[j])r--;             }             Min=min(Min,result);         }         printf("%lld\n",Min);     }     return 0;

}

兩個注意點:最大值的設定不要設為1e18  考慮到所有數的和可能剛好是一個很大的素數 此時所打的素數表可能不夠整除,此時輸出的結果必然是所有數的和減去最大的數(將其他石頭都移到這個最大的堆上)所以要將Min設定為總和減去最大堆。(wa了八發)

不能直接統計對每個堆的最小運算元(會wa具體原因不知)