ROS开始做基础题故尝试水题解——洛谷P1734最大约数和

最近突然发现这道题在我的洛谷账号上为40分,打开一看发现是去年刚学dfs还没学dp的时候用dfs写的

然后已经学习了dp的我发现这道题如此简单

先粘贴一下我去年写的dfs代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int ans=0;
int s;
int ys(int x){
    int sum=0;
    if(x==1) return 0;
    for(int i=1;i<x;i++){
        if(x%i==0){
            sum+=i;
        }
    }
    return sum;
}
void f(int x,int y,int z){
    if(x==0||z==0) {
        if(y>ans){
            ans=y;
            //cout<<"one turn"<<endl;
            return ;
        }
        return ;
    }
    if(x<=z) {
    //cout<<"one time's change"<<endl;
    f(x-1,y+ys(x),z-x);
    }
    f(x-1,y,z);
    return ;
} 
int main()
{
    //cout<<ys(3)<<endl;
    cin>>s;
    f(s,0,s);
    cout<<ans;
    return 0;
}

 

 非常直观,这道题就是直接用dfs枚举出所有情况所以T掉6个点也是很正常的

所以直接考虑使用dp

一维dp数组状态:dp[i]表示当s==i时的最大约数之和

用num(i)表示i的所有除了i的约数之和

那么很容易写出状态转移方程:dp[i]=max(dp[i],num(i)),dp[i]=max(dp[i],dp[k]+dp[i-k])(k表示所有从1到i-1的正整数)

初始状态:dp[1]=0

易得AC代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int dp[1010]; 
int num(int);
int main(){
    scanf("%d",&n);
    dp[1]=0;
    for(int i=2;i<=n;i++){
        int tmp=num(i);
        dp[i]=max(dp[i],tmp);
        for(int j=1;j<i;j++){
            dp[i]=max(dp[i],dp[j]+dp[i-j]);
        }
    }
    printf("%d",dp[n]);
    return 0;
}
int num(int x){
    int sq=sqrt(x),k=-x;
    for(int i=1;i<=sq;i++){
        if(x%i==0) k+=i,k+=x/i;
    }
    if(sq*sq==x) k-=sq;    //如果是完全平方数就减1 
    return k;
}

 

 


THE END.

 

posted @ 2020-08-31 15:37  Robertspot  阅读(226)  评论(0编辑  收藏  举报