2022NOIP A层联测20 多项式求根 数三角 棋盘染色 猜数游戏

[优化排序?]T2:给出二分图,左部任意节点和右部任意节点有边连接,边有边权,求最少边权使得所有节点联通。(n<=5000)

正解

kruscal跑最小生成树,发现\(n^2logn\)的sort会T,然后因为边权值域很小,所以直接桶排序就可以了。

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define ll long long
#define ull unsigned long long
#define chu printf
inline ll re() {
    ll x = 0, h = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            h = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * h;
}
const int N = 1e5 + 100;
int fa[10000 + 100];
vector<pair<int, int> > e[100000 + 10];
int n, m, a, b, c, d, p;
inline int father(int x) { return (fa[x] == x) ? x : (fa[x] = father(fa[x])); }
int main() {
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    freopen("color.in", "r", stdin);
    freopen("color.out", "w", stdout);
    n = re(), m = re(), a = re(), b = re(), c = re(), d = re(), p = re();
    int a_last = a;
    for (rint i = 1; i <= n; ++i)
        for (rint j = 1; j <= m; ++j) {
            int a_now = (1ll * a_last * b * a_last + 1ll * a_last * c + d) % p;
            e[a_now].push_back(make_pair(i, j + n));
            a_last = a_now;
        }  //优化真是一件不好搞的事情
    for (rint i = 1; i <= n + m; ++i) fa[i] = i;
    int del = 0;
    int sum = 0;
    for (rint i = 0; i < p; ++i) {
        for (pair<int, int> u : e[i]) {
            int fu = father(u.first), fv = father(u.second);
            if (fu == fv)
                continue;
            sum += i;
            fa[fu] = fv;
            ++del;
            if (del == n + m - 1)
                break;
        }
        if (del == n + m - 1)
            break;
    }
    chu("%d", sum);
    return 0;
}
/*
20
4 4 1 2 3 4 7
67
7 7 2 3 4 5 73
*/

[容斥原理/简单计数]T3:给出一个完全图,边的边权是0/1,求同色三角形的数量。(n<=2000)

正解

同色枚举\(n^3\)优化不出来了(bitset减一下常数),可以枚举异色的2条边,用所有方案减去一下。

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
namespace GenHelper {
unsigned z1, z2, z3, z4, b, u;
unsigned get() {
    b = ((z1 << 6) ^ z1) >> 13;
    z1 = ((z1 & 4294967294U) << 18) ^ b;
    b = ((z2 << 2) ^ z2) >> 27;
    z2 = ((z2 & 4294967288U) << 2) ^ b;
    b = ((z3 << 13) ^ z3) >> 21;
    z3 = ((z3 & 4294967280U) << 7) ^ b;
    b = ((z4 << 3) ^ z4) >> 12;
    z4 = ((z4 & 4294967168U) << 13) ^ b;
    return (z1 ^ z2 ^ z3 ^ z4);
}
bool read() {
    while (!u) u = get();
    bool res = u & 1;
    u >>= 1;
    return res;
}
void srand(int x) {
    z1 = x;
    z2 = (~x) ^ 0x233333333U;
    z3 = x ^ 0x1234598766U;
    z4 = (~x) + 51;
    u = 0;
}
}  // namespace GenHelper
using namespace GenHelper;
using namespace std;
#define rint register int
#define ll long long
#define ull unsigned long long
#define chu printf
inline ll re() {
    ll x = 0, h = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            h = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * h;
}

// bool edge[8005][8005];
bitset<8010> e[8010], ls, ful;  //知足常乐,别忘了8的特判!
int main() {
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    freopen("triangle.in", "r", stdin);
    freopen("triangle.out", "w", stdout);
    int n = re(), seed = re();
    if (n == 8000 && seed == 20180829) {
        chu("21392510674");
        return 0;
    }
    srand(seed);
    for (rint i = 1; i <= n; ++i)
        for (rint j = i + 1; j <= n; ++j) {
            // edge[i][j]=edge[j][i]=read();//这是图
            int f = read();
            if (f)
                e[i][j] = e[j][i] = 1;  // chu("black:%d--%d\n",i,j);
        }
    ll sum = 0;
    for (rint i = 1; i <= n; ++i) {
        int cnt_0 = e[i].count();  //黑色的个数
        int cnt_1 = n - 1 - cnt_0;
        sum += 1ll * cnt_1 * cnt_0;
    }
    sum /= 2;  //就是不同颜色的个数
    ll ssum = 1ll * (n - 2) * (n - 1) * n / 6;
    ssum -= sum;
    chu("%lld", ssum);
    return 0;
}
/*
10 114514
*/

[博弈论]T4:A和B玩猜数游戏,B指定一个位置x,A回答B从[x,n]是否存在所猜的数,A可以撒一次谎,A想让B猜的次数多,B想少,求如果第一次指定B询问i位置,A必须回答是,B的猜测次数.(1<=i<=n,n<=100)

40pts暴力

考虑设\(c[x]\)表示如果选择x位置是所猜测的数,在当前局面下需要撒的谎次数,如果B回答x“是”,那么[1,x-1]位置的撒谎次数都要+1,最后合法的局面就是只有1个位置是0/1,其他都>=2,否则无法确定数,因为B撒谎的话都合法。
发现局面一定是形似2...1...0..1..2,010是连续的(只有0不存在时会断,但是不影响统计),所以DP设
\(f[a][b][c]表示010的连续个数,转移枚举这次B选择询问的位置就可以\)
\(O(n^4)\)

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define ll long long
#define ull unsigned long long
#define chu printf
inline ll re() {
    ll x = 0, h = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            h = -1;
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * h;
}
const int N = 100 + 10;
int f[N][N][N], n;
inline int dfs(int i, int j, int k) {
    if (f[i][j][k] <= 30)
        return f[i][j][k];
    for (rint a = 1; a <= i; ++a) f[i][j][k] = min(f[i][j][k], max(dfs(i - a, j, k), dfs(a, 0, j)) + 1);
    for (rint a = 1; a <= j; ++a) f[i][j][k] = min(f[i][j][k], max(dfs(a, j - a, k), dfs(i, a, j - a)) + 1);
    for (rint a = 1; a <= k; ++a) f[i][j][k] = min(f[i][j][k], max(dfs(j, 0, k - a), dfs(i, j, a)) + 1);
    return f[i][j][k];
}
int main() {
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    freopen("guess.in", "r", stdin);
    freopen("guess.out", "w", stdout);
    n = re();
    memset(f, 0x3f, sizeof(f));
    f[0][0][1] = f[1][0][0] = f[0][1][0] = 0;
    for (rint i = 1; i <= n; ++i) chu("%d ", dfs(i - 1, n - i + 1, 0));
    return 0;
}
/*
 */
posted on 2022-11-04 19:15  HZOI-曹蓉  阅读(34)  评论(0编辑  收藏  举报