gym 100520E

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;
}

猜你喜欢

转载自blog.csdn.net/qq_18869763/article/details/83962927