n皇后问题,n=4000000,5s

好像有构造方法,但是爬山的话就可以用经典的那个做法,就是随机交换两个列皇后的行编号,然后看每条斜线皇后个数的平方和是否变小,如果变小,就交换,这个100000随便跑,但是4000000比较困难,所以需要再用很多技巧优化,最后可以在五秒内完成。

code

#include <bits/stdc++.h>
#define FOR(i, j, k) for(int i = (j); i <= (k); ++i)
#define ROF(i, j, k) for(int i = (j); i >= (k); --i)
#define vi vector <int>
#define ll long long
#define pii pair<int, int>
#define sz(a) ((int) (a).size())
#define me(a, x) memset(a, x, sizeof(a))
#define eb emplace_back
using namespace std;
const int N = 4000000 + 10;
int n;
int p[N];
int buc1[N * 2], buc2[N * 2];
vector<int> id1[N * 2], id2[N * 2];
int vis[N * 2];
ll sum = 0;
void mdf1(int x, int v) {
    sum -= (ll)buc1[x] * buc1[x];
    buc1[x] += v;
    sum += (ll)buc1[x] * buc1[x];
}
void mdf2(int x, int v) {
    sum -= (ll)buc2[x] * buc2[x];
    buc2[x] += v;
    sum += (ll)buc2[x] * buc2[x];
}
void mdf(int x, int v) {
    mdf1(x + p[x], v);
    mdf2(x - p[x] + n, v);
}
mt19937 gen(__builtin_ia32_rdtsc());
int rd(int l, int r) {
    uniform_int_distribution<int> rng(l, r);
    return rng(gen);
}
void Swap(int u, int v) {
    mdf(u, -1), mdf(v, -1);
    swap(p[u], p[v]);
    mdf(u, 1), mdf(v, 1);
}
vector<int> id;
int check(int x) {
    return buc1[x + p[x]] == 1 && buc2[x - p[x] + n] == 1;
}
int Try(int u, int v) {
    ll tsum = sum;
    Swap(u, v);
    if(tsum < sum) {
        Swap(u, v);
        return 0;
    }
    return 1;
}
void del(int u) {
    vector<int> &v1 = id1[u + p[u]];
    v1.erase(find(v1.begin(), v1.end(), u));
    vector<int> &v2 = id2[u - p[u] + n];
    v2.erase(find(v2.begin(), v2.end(), u));
}
void ins(int u) {
    vector<int> &v1 = id1[u + p[u]];
    v1.push_back(u);
    vector<int> &v2 = id2[u - p[u] + n];
    v2.push_back(u);
}
void Check(int x) {
    for(auto u : id1[x + p[x]]) {
        if(!check(u) && !vis[u]) {
            id.emplace_back(u);
            vis[u] = 1;
        }
    }
    for(auto u : id2[x - p[x] + n]) {
        if(!check(u) && !vis[u]) {
            id.emplace_back(u);
            vis[u] = 1;
        }
    }
}
void shake() {
    int u = id[rd(0, sz(id) - 1)], v;
    do {
        v = rd(1, n);
    } while(vis[v]);
    ll tsum = sum;
    Swap(u, v);
    if(tsum < sum) {
        Swap(u, v);
    } else {
        swap(p[u], p[v]);
        del(u), del(v);
        swap(p[u], p[v]);
        ins(u), ins(v);
        Check(u), Check(v);
    }
}
void pretrain() {
    int cnt = 0;
    while(sum > 2 * n) {
        cnt += 1;
        int u, v;
        do {
            swap(id[rd(0, sz(id) - 1)], id[sz(id) - 1]);
            swap(id[rd(0, sz(id) - 2)], id[sz(id) - 2]);
            if(check(id[sz(id) - 1])) {
                vis[id.back()] = 0;
                id.pop_back();
                continue;
            }
            if(check(id[sz(id) - 2])) {
                swap(id[sz(id) - 1], id[sz(id) - 2]);
                vis[id.back()] = 0;
                id.pop_back();
                continue;
            }
            u = id[sz(id) - 1], v = id[sz(id) - 2];
            break;
        } while(1);
        ll tsum = sum;
        Swap(u, v);
        if(tsum < sum) {
            Swap(u, v);
        }
        if(sz(id) <= 100) break;
        // if(cnt % 1000000 == 0) cout << cnt << " " << sum << " " << sz(id) << endl;
    }
}
int main() {
    n = 4000000;
    FOR(i, 1, n) p[i] = i, id.emplace_back(i), vis[i] = 1;
    shuffle(p + 1, p + n + 1, gen);
    shuffle(id.begin(), id.end(), gen);
    FOR(i, 1, n) {
        mdf(i, 1);
    }
    pretrain();
    FOR(i, 1, n) {
        id1[i + p[i]].emplace_back(i);
        id2[i - p[i] + n].emplace_back(i);
    }
    int cnt = 0;
    ll presum = -1;
    while(sum > 2 * n) {
        cnt += 1;
        int u, v;
        do {
            swap(id[rd(0, sz(id) - 1)], id[sz(id) - 1]);
            swap(id[rd(0, sz(id) - 2)], id[sz(id) - 2]);
            if(check(id[sz(id) - 1])) {
                vis[id.back()] = 0;
                id.pop_back();
                continue;
            }
            if(check(id[sz(id) - 2])) {
                swap(id[sz(id) - 1], id[sz(id) - 2]);
                vis[id.back()] = 0;
                id.pop_back();
                continue;
            }
            u = id[sz(id) - 1], v = id[sz(id) - 2];
            break;
        } while(1);
        ll tsum = sum;
        Swap(u, v);
        if(tsum < sum) {
            Swap(u, v);
        } else {
            swap(p[u], p[v]);
            del(u), del(v);
            swap(p[u], p[v]);
            ins(u), ins(v);
            Check(u), Check(v);
        }
        if(sz(id) <= 100) shake();
        if(cnt % 100000 == 0) {
            if(sum == presum) {
                // break;
            }
            presum = sum;
        }
        // if(cnt % 1000000 == 0) cout << cnt << " " << sum << " " << sz(id) << endl;
    }
    // while(sum > 2 * n) {
    //     cnt += 1;
    //     int u, v;
    //     do {
    //         u = rd(1, n), v = rd(1, n);
    //     } while(u == v);
    //     ll tsum = sum;
    //     Swap(u, v);
    //     if(tsum < sum) {
    //         Swap(u, v);
    //     }
    //     // if(cnt % 100000 == 0) {
    //     //     if(sum == presum) {
    //     //         break;
    //     //     }
    //     //     presum = sum;
    //     // }
    //     if(cnt % 1000000 == 0) cout << cnt << " " << sum << " " << sz(id) << endl;
    // }
    cout << cnt << " " << sum << " " << sz(id) << endl;
    // for(auto u : id) cout << u <<" " << p[u] << endl;
    cout << "Done !" << endl;
}
posted @ 2025-05-30 22:20  SegmentTree  阅读(14)  评论(0)    收藏  举报