题目:http://poj.org/problem?id=3590
bzoj 1025 的弱化版。大概一样的 dp 。
输出方案的时候小的环靠前。不用担心 dp 时用 > 还是 >= 来转移,因为答案的那个 lcm 有唯一分解。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=105,M=30; int T,n,dp[M][N],dy[M][N],pri[M],cnt,sta[M],top,ans,sm; bool vis[N]; int Mx(int a,int b){return a>b?a:b;} void init() { for(int i=2;i<=100;i++) { if(!vis[i])pri[++cnt]=i; for(int j=1;j<=cnt&&i*pri[j]<=100;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } } void print() { printf("%d ",ans); sort(sta+1,sta+top+1); for(int i=1;i<=n-sm;i++)printf("%d ",i); for(int i=1,cr=n-sm+1;i<=top;i++) { for(int j=cr+1,k=1;k<sta[i];j++,k++) printf("%d ",j); printf("%d ",cr); cr+=sta[i]; } puts(""); } int main() { init(); scanf("%d",&T); while(T--) { scanf("%d",&n); memset(dp,0,sizeof dp); memset(dy,0,sizeof dy); dp[0][0]=1; int i; for(i=1;i<=cnt&&pri[i]<=n;i++) { for(int j=0;j<=n;j++)dp[i][j]=dp[i-1][j]; for(int k=1,p=pri[i];k<=6&&p<=n;k++,p*=pri[i])//&&p<=n!! or exceed int for(int j=p,d;j<=n;j++) if((d=dp[i-1][j-p]*p)>dp[i][j])//>? >=? no influence for 'only' { dp[i][j]=d; dy[i][j]=p; } } i--; top=0; ans=0; for(int j=0;j<=n;j++) if(dp[i][j]>ans)ans=dp[i][j],sm=j; for(int t=i,cr=sm;t;t--) { if(!dy[t][cr])continue; sta[++top]=dy[t][cr]; cr-=dy[t][cr]; } print(); } return 0; }