poj 3590 The shuffle Problem——DP+置换

题目: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;
}
原文地址:https://www.cnblogs.com/Narh/p/10061083.html