1. 程式人生 > >HDU 4896 Minimal Spanning Tree(矩陣快速冪)

HDU 4896 Minimal Spanning Tree(矩陣快速冪)

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef __int64 ll;

int tot, vis[11];
map mp;
string zt[55];
int changeto[55][55];

void dfs(int c, string str) {
    if(c == 6) {
        mp[str] = tot;
        zt[tot] = str;
        tot++;
        return ;
    }
    if(vis[c]) {
        dfs(c+1, str);
        return ;
    }
    int a[6];
    vis[c] = 1;
    str += c + '0';
    int tot = 0;
    for(int i = c+1;i <= 5; i++) if(!vis[i]) {
        a[tot++] = i;
    }
    int full = (1<>j&1) {
            vis[a[j]] = 1;
            nxt += a[j] + '0';
        }
        nxt += ',';
        dfs(c+1, nxt);
        for(int j = 0;j < tot; j++) if(i>>j&1)
            vis[a[j]] = 0;
    }
    vis[c] = 0;
}

int find_fa(int fa[], int x) {
    return fa[x] = (fa[x] == x ? x : find_fa(fa, fa[x]));
}

void Union(int fa[], int x, int y) {
    x = find_fa(fa, x);
    y = find_fa(fa, y);
    if(x != y)  fa[x] = y;
}

void init() {
    memset(vis, 0, sizeof(vis));
    tot = 0;
    dfs(1, "");
    for(int i = 0;i < tot; i++) {
        int fa[8];
        for(int j = 1;j <= 6; j++)  fa[j] = j;
        for(int j = 1;j < zt[i].size(); j++) if(zt[i][j]!=','&&zt[i][j-1]!=',')
            Union(fa, zt[i][j]-'0', zt[i][j-1]-'0');
        for(int j = 1;j <= 6; j++)  fa[j] = find_fa(fa, j);
        int full = (1<<5)-1;
        for(int j = 0;j <= full; j++) {
            int ff[8];
            for(int k = 1;k <= 6; k++)  ff[k] = fa[k];
            for(int k = 0;k < 5; k++) if(j>>k&1)
                Union(ff, 6, 6-k-1);
            for(int k = 1;k <= 6; k++)  ff[k] = find_fa(ff, k);
            bool flag = true;
            string nxt = "";
            memset(vis, 0, sizeof(vis));
            for(int k = 1;k <= 6; k++) if(!vis[k]){
                int sum = 0;
                for(int l = k;l <= 6; l++) if(ff[k]==ff[l])
                    sum++;
                if(k == 1 && sum == 1) {
                    flag = false;
                    break;
                }
                if(k == 1)  continue;
                for(int l = k;l <= 6; l++)if(ff[k]==ff[l]){
                    vis[l] = 1;
                    if(l > 1)   nxt += l-1+'0';
                }
                nxt += ',';
            }
            if(!flag)   changeto[i][j] = -1;
            else    changeto[i][j] = mp[nxt];
        }
    }
}

const ll INF = 1LL<<60;
const int D = 52;
struct matrix {
    ll a[D][D];

    matrix() {
        memset(a, 0, sizeof(a));
    }

    matrix operator * (const matrix&b)const {
        matrix ret;
        for(int i = 0;i < D; i++) {
            for(int j = 0;j < D; j++) {
                ret.a[i][j] = INF;
                for(int k = 0;k < D; k++)
                    ret.a[i][j] = min(ret.a[i][j], a[i][k]+b.a[k][j]);
            }
        }
        return ret;
    }

    void print() {
        puts("");
        for(int i = 0;i < D; i++) {
            for(int j = 0;j < D; j++)
                printf("%d ", a[i][j]);
            puts("");
        }
        puts("");
    }
};

int val[11], n, seed;

bool input() {
    return scanf("%d%d", &n, &seed) == 2;
}

matrix get(int d) {
    matrix ret;
    for(int i = 0;i < D; i++)
        for(int j = 0;j < D; j++)
            ret.a[i][j] = INF;
    for(int i = 0;i < D; i++) {
        int full = (1<>k & 1)
                add += val[k];
            ret.a[i][changeto[i][j]] = min(ret.a[i][changeto[i][j]], add);
        }
    }
    return ret;
}

matrix fuck[11];

ll solve() {
    if(n == 1)  return 0;
    const int MOD = 2333333;
    matrix ans;
    for(int i = 0;i < D; i++) ans.a[0][i] = INF;
    ans.a[0][51] = 0;
    int x = seed;
    for(int i = 2;i <= 5; i++) {
        x = x*907%MOD;
        int T = x;
        for(int j = 1;j <= i-1; j++) {
            x = x*907%MOD;
            int w = T^x;
            val[i-j-1] = w;
        }
        matrix tmp = get(i-1);
        ans = ans*tmp;
        if(i == n) {
            return ans.a[0][51];
        }
    }
    memset(fuck[0].a, 0, sizeof(fuck[0].a));
    for(int i = 6;i <= 15; i++) {
        x = x*907%MOD;
        int T = x;
        for(int j = i-5;j <= i-1; j++) {
            x = x*907%MOD;
            int w = T^x;
            val[i-j-1] = w;
        }
        matrix tmp = get(5);
        if(i > 6)   fuck[i-5] = fuck[i-5-1]*tmp;
        else    fuck[i-5] = tmp;
        if(i == n) {
            ans = ans*fuck[i-5];
            return ans.a[0][51];
        }
    }
    int Time = (n-5)/9;
    while(Time) {
        if(Time&1)  ans = ans*fuck[9];
        fuck[9] = fuck[9]*fuck[9];
        Time >>= 1;
    }
    if((n-5)%9 > 0) ans = ans*fuck[(n-5)%9];
    return ans.a[0][51];
}

int main() {
    init();
    while(input()) {
        printf("%I64d\n", solve());
    }
    return 0;
}