生词:
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;
}