生詞:
factorization 因數分解;P-th power p次冪;tie 平局,兩種方案相同;
sequence { a1, a2, … aK } is said to be larger than { b1, b2, … bK } if there exists 1<=L<=K such that ai=bi for ibL
這句是按字典序排序的意思, { a1, a2, … aK }比 { b1, b2, … bK }大就是指{ a1, a2, … aK }的字典序比 { b1, b2, … bK }大。
題目差點沒讀懂。讀到輸出格式倒是大致明白了。第一反應不會,但是先試試。
慘不忍睹,編譯不過的第一版:
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
vector<int> s,smax;
int basummax=0;
int N,K,P;
/*標答的思路是預先生成需要的平方數數列,因此只需要從大到小遞歸即可實現遞減排序*/
bool cmp(int a,int b){
return a>b;
}
//不要在找到一組解後才判斷字典序關係,應該讓index從大到小選擇
vector<int> zidianxu(vector<int> s,vector<int> smax){
vector<int> res;
/*正確寫法:
vector<int>::iterator it=s.begin();
sort(it,it+s.size(),cmp);*/
sort(s,s+s.size(),cmp);//錯誤!
sort(smax,smax+smax.size(),cmp);//錯誤!
for(int i=0;i<s.size();i++){
if(s[i]==smax[i]){
continue;
}else{
s[i]>smax[i]?res=s:res=smax;
break;
}
}
return res;
}
void DFS(int index, int sum){
if(index>K)return;
if(sum>N)return;
if(sum==N&&index==K){
int basum=0;//底數和
/*假如有5個方案,計算底數和的時間複雜度是O(K)(取時間複雜度最大的步驟的複雜度),容易超時。如果把底數和作爲一個參數,則複雜度爲O(1)*/
for(vector<int>::iterator it=s.begin();it!=s.end();it++){
basum+=*it;
}
if(basum>basummax){
smax=s;//vector間可以直接賦值
}else if(bsum==basummax){
smax=zidianxu(s,smax);
} else{
return;
}
}
/*我的想法是N=400,P最小=2的情況時,底數選取的範圍最大:1~20,可覆蓋所有情況,但這樣時間複雜度極高。標答的思路是當輸入N,P時,將所有小於N的平方數計算並存儲結果,然後從中選K個。另一個錯誤是s[index]中的數可以相同,我沒有枚舉這種情況*/
for(int i=1;i<20;i++){
s[index]=i;//vector不可以這樣賦值,只能用push_back()!
/*假如有5個方案,計算底數和的時間複雜度是O(K)(取時間複雜度最大的步驟的複雜度),如果把底數和作爲一個參數,則複雜度爲O(1)*/
DFS(index+1,sum+pow(i,P));
/*分析遞歸的時候分析1:遞歸有幾個參數;2.遞歸的時候有幾個分支,分支參數的變化。*/
continue;
}
}
int main(){
scanf("%d %d %d",&N,&K,&P);
DFS(0,0);
if(smax.empty()){
printf("Impossible");
} else{
printf("%d =",N);
for(int i=0;i<K;i++){
printf(" %d^%d",smax[i],P);
if(i<k-1){
printf(" +");
}
}
}
return 0;
}
把自己的想法儘快用代碼表達出來,反正通過的可能幾乎沒有。之所以自己先寫一遍,是爲了儘可能多的找到自己的薄弱點,雖然從頭到腳都是弱點。至少if-else,for(){輸出}我還是能寫好的。
下面是標答:
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
int n,k,p,maxFacSum=-1;//最大底數和
vector<int> fac,ans,temp;//預處理的平方數,最優底數序列,當前底數序列
/*int power(int x){
int ans=1;
for(int i=0;i<p;i++){
ans*=x;
}
return ans;
}*/
//預處理fac數組
void init(){
int i=0,temp=0;
while(temp<=n){
fac.push_back(temp);
temp=pow(++i,p);
}
}
void DFS(int index,int nowK,int sum,int facSum){
if(sum==n&&nowK==k){
if(facSum>maxFacSum){
ans=temp;
maxFacSum=facSum;
}
return;
}
if(sum>n||nowK>k)return;
if(index-1>=0){
temp.push_back(index);
DFS(index,nowK+1,sum+fac[index],facSum+index);
temp.pop_back();
DFS(index-1,nowK,sum,facSum);
}
}
int main(){
scanf("%d%d%d",&n,&k,&p);
init();
DFS(fac.size()-1,0,0,0);
if(maxFacSum==-1)printf("Impossible\n");
else{
printf("%d = %d^%d",n,ans[0],p);
for(int i=1;i<ans.size();i++){
printf(" + %d^%d",ans[i],p);
}
}
return 0;
}
標答的思路就是先生成備選平方數,然後再用DFS輪。
我的思路是想到那寫到那,全部用最笨最暴力的枚舉解決。
傻。
默寫失敗第一版,“運行超時”
#include<cstdio>
#include<vector>
using namespace std;//常忘1
vector<int> powSes,tempRes,maxRes;//vector<int>常忘2
int n,k,p,maxKSum=-1;
int power(int x){
int ans=1;
for(int i=0;i<p;i++){
ans=ans*x;
}
return ans;
}
void init(){
int temp=0;
for(int i=0;;i++){//爲了保證第i位的數據是i^p,所以第0位的數據是0
temp=power(i);
if(temp>n)return;
powSes.push_back(temp);
}
}
void DFS(int index,int sum,int kSum,int kc){
if(sum==n&&kc==k){
if(kSum>maxKSum){
maxRes=tempRes;
maxKSum=kSum;
}/*else if(kSum==maxKSum){
for(int i=0;i<k;i++){
if(maxRes[i]<tempRes[i]){
maxRes=tempRes;
break;
}else if(maxRes[i]>tempRes[i]){
break;
}
}將次方數組從大到小選數,後面的滿足條件的序列其字典序必然小於前面先滿足條件的序列
}*/
return;
}
if(sum>n||kc>k)return;
/*while(index-1>=0){//假設index是5,兩條DFS子函數都執行完了,因爲while(5-1>=0),故又重複執行一遍,死循環。
tempRes.push_back(powSes[index]);
要保存的是底數序列,不是次方序列!
DFS(index,sum+powSes[index],kSum+index,kc+1);
tempRes.pop_back();
DFS(index-1,sum,kSum,kc);
}*/
if(index-1>=0){
tempRes.push_back(index);
DFS(index,sum+powSes[index],kSum+index,kc+1);
tempRes.pop_back();
DFS(index-1,sum,kSum,kc);
}
}
int main(){
scanf("%d %d %d",&n,&k,&p);
init();
DFS(powSes.size()-1,0,0,0);
if(maxKSum==-1)printf("Impossible");
else{
printf("%d =",n);
for(int i=0;i<k;i++){
printf(" %d^%d",maxRes[i],p);
if(i<k-1){
printf(" +");
}
}
}
return 0;
}