dp[ i ] [ j ]表示当前考虑在第i个位置填第j个数的最小值,那么dp[ i ] [ k ]应该由dp[ i-1 ] [ j ]转移过来。而不同的位置的后一个数可以填的数是有限制的。根据题意可以填的数,相邻的两个位置,左右一定对应一个相等的区间长度(且一定是2的次幂)。这个范围内表示可以相邻的数。并且这样的情况不会出现(在i这个位置填k,并且k在之前的i'位置出现过)。
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MX = 4100;
int dp[MX][MX],last[MX][MX];
int ans[MX];
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#else
freopen("elegant.in","r",stdin);
freopen("elegant.out","w",stdout);
#endif // LOCAL
int n;
while(~scanf("%d",&n) && n){
int a,b,c,m;
scanf("%d%d%d%d",&a,&b,&c,&m);
for(int i = 1; i <= n; ++i)
for(int j = 0; j<= n; j++)
dp[i][j] = INF;
for(int i = 0; i < n-1; ++i){
int len = 0;
while((i>>len)&1) ++len;
for(int j = 0; j < n; ++j){
int st = ((j>>len)^1)<<len;
for(int k = st; k < st+(1<<len); ++k){
int w = dp[i][j] + (a*j+b*k+c*(j^k))%m;
if(w < dp[i+1][k]){
dp[i+1][k] = w;
last[i+1][k] = j;
}
}
}
}
int sum = dp[n-1][0], now = 0;
for(int i = 1; i < n; i++){
if(sum > dp[n-1][i]) sum = dp[n-1][i], now = i;
}
for(int i = n-1; i >= 0; now = last[i][now] ,i--) ans[i] = now;
printf("%d\n",sum);
for(int i = 0; i < n; i++)
printf("%d%c",ans[i]," \n"[i==n-1]);
}
return 0;
}