1. 程式人生 > >CodeForces 1081E Missing Numbers <<數學

CodeForces 1081E Missing Numbers <<數學

題意

有一個字首和是平方數的序列,也就是一個嚴格遞增平方數的差分序列,奇數項丟了,給出偶數項,要求輸出所有項。

思路

首先列出一個式子,對於題設差分序列中的一項c,必定要滿足有$a^2-b^2=c$,即$(a-b)\times(a+b)=c$,那麼現在已知c,如何定出a和b呢,很容易想到把c因式分解,使$(a-b)$,$(a+b)$為c的一對因子即可。設其中一個因子為x,不妨設x為一對之中大的那個因子,那麼令$a+b=x$,$a-b=c/x$聯立兩式可解得,$2a=x+c/x$,$2b=x-c/x$。那麼a,b存在的充分必要條件就是這對因子和(差)為偶數即可,換言之,一對和(差)為偶數的因子即可構造出c,且其他所有的數都不能構造出c(不會證明,可能是錯的)。

推進到這裡,我們就可以開始構造題目要求的序列了。針對每個數,我們都選擇構造儘量小的平方數,這樣保證在之後的構造中能夠有更多的選擇。在構造當前數的選擇上,已經有的字首和為now,那麼當前數就為$b^2-now^2$。

進行上述步驟,哪步進行不下去就No。

程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1e5+7;
 4 int arr[maxn];
 5 vector<int> fac[maxn];
 6 long long ans[maxn];
7 int main() 8 { 9 int n; 10 scanf("%d",&n); 11 n/=2; 12 for(int i=0;i<n;i++) 13 { 14 scanf("%d",&arr[i]); 15 for(int j=1;j<sqrt(arr[i]);j++) 16 { 17 if(arr[i]%j==0) 18 fac[i].push_back(arr[i]/j); 19 }
20 sort(fac[i].begin(),fac[i].end()); 21 } 22 int now=0; 23 bool flag=1; 24 for(int i=0;i<n;i++) 25 { 26 for(int j=0;j<fac[i].size();j++) 27 { 28 int a=fac[i][j],b=arr[i]/a; 29 if((a+b)%2) continue; 30 int aa=(a+b)/2,bb=(a-b)/2; 31 if(bb<=now) continue; 32 else{ 33 ans[i]=1LL*bb*bb-1LL*now*now; 34 now=aa; 35 break; 36 } 37 } 38 if(ans[i]==0) flag=0; 39 if(!flag) break; 40 } 41 if(!flag) puts("No"); 42 else { 43 puts("Yes"); 44 for(int i=0;i<n;i++) 45 { 46 printf("%lld %d ",ans[i],arr[i]); 47 } 48 } 49 50 }

後記

推公式真好玩。