B

思维题,难在模型的转化。

对于一个矩阵,将其理解为一个二分图:行和列。

此时,对于每一个点,它就是二分图里的边:连接一个行和一个列。

如果我选择一些点,使得所有的行和列上都存在点,这就是解的必要条件。

但似乎只靠这一条件并不充分,不过能过。

#include <bits/stdc++.h>
#define sc(x) scanf("%lld", &(x))
#define pr(x) printf("%lld\n", (x))
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
typedef long long ll;
const int N = 5e3;
const int mod = 1e9 + 7;
ll n, m, a, b, c, d, p;
struct node {
    int x, y;
    ll w;
    bool operator< (const node & o)const{
        return w < o.w;
    }
} ar[N * N + 1];
int fa[N * 2 + 1];
inline void init(int n) {
    for (int i = 1; i <= n; ++i) fa[i] = i;
}
inline int Find(int x) {
    if (x != fa[x]) fa[x] = Find(fa[x]);  //路径压缩
    return fa[x];
}
inline void merge(int x, int y) { fa[Find(y)] = Find(x); }
signed main() {
    sc(n), sc(m), sc(a), sc(b), sc(c), sc(d), sc(p);
    if (n == 0 or m == 0) return cout << 0, 0;
    ar[0].w = a;
    rep(i, 1, n) rep(j, 1, m) {
        int id = m * (i - 1) + j;
        ar[id] = {i, j,
                  (ar[id - 1].w * ar[id - 1].w * b + ar[id - 1].w * c + d) % p};
    }
    sort(ar + 1, ar + 1 + m * n);
    init(n + m);
    ll res = 0, cnt = 0;
    rep(i, 1, n * m) {
        if (Find(ar[i].x) != Find(ar[i].y + n))
            res += ar[i].w, ++cnt, merge(ar[i].x, ar[i].y + n);
        if (cnt == n + m - 1) break;
    }
    pr(res);
    return 0;
}

按这样答案不会出错,不过这一选出来的点是无法满足的,但对于这一答案,可能一定存在满足的解。

一组数据:

8 9 9 6 1 5 7

图片说明

E

图片说明

队友写的,核心思路是递推第二个数

#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<int> g;
const int N = 1e6 + 5;
int a[N];
signed main(){
    int t, n;
    cin >> t;
    for (int k = 2; k <= 1e6; ++k) {
        a[1] = k;
        for (int i = 2; i <= 60 ; ++i) {
            a[i] = k * k * a[i - 1] - a[i - 2];
            if(a[i] > 1e18 || a[i] < 0)  break;
            g.push_back(a[i]);
        }
    }
    sort(g.begin(),g.end());
    while(t--){
        cin >> n;
        cout << upper_bound(g.begin(), g.end(), n) - g.begin() + 1 << '\n';
    }
    return 0;
}

F

大模拟。

我的思路是枚举取值后,再枚举逆波兰表达式。

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
typedef long long ll;
int n;
double tar;
vector<vector<int>> res;
const double eps = 1e-6;
int opc[] = {'+', '-', '*', '/'};
inline bool isOper(int x) {  // 是不是运算符
    return x == '+' || x == '-' || x == '*' || x == '/';
}
inline bool isInt(double x) {  // 是不是整数
    return fabs(x - int(x)) <= eps || fabs(x - ceil(x)) <= eps;
}
inline bool eq(double x) { return fabs(x - tar) <= eps; }  // 等于结果
inline bool cal(double a, double b, int op, double &res) {  // 计算一个小算式
    if (op == '/') {
        res = a / b;
        if (!isInt(res)) return 1;
    } else if (op == '*')
        res = a * b;
    else if (op == '+')
        res = a + b;
    else
        res = a - b;
    return 0;
}
int deal(vector<int> a) {  //计算一个逆波兰表达式
    stack<double> st;
    double res = 0;
    bool f = 0;
    for (int i : a) {
        if (!isOper(i))
            st.push(i);
        else {
            if (st.size() < 2) return 0;  // 鲁棒性
            double x = st.top();
            st.pop();
            double y = st.top();
            st.pop();
            if (i == '/' && fabs(y) <= eps) return 0;  // 避免除零
            if (cal(x, y, i, res)) f = 1;              // 出现分数解
            st.push(res);
        }
    }
    if (st.size() > 1) return 0;  // 鲁棒性
    if (abs(res - tar) > eps) return 0;
    return 1 + f;
    // 0 : 不为 m
    // 1 : 为m 但无分数
    // 2 : 为m 且有分数
}
void dfs(vector<int> &a, vector<int> &pre, int &status, int ch = 0) {
    // 采用引用 + 回溯 枚举逆波兰表达式 避免MLE
    if (status == 1) return;  // 一旦出现非分数解,一切都不用算了
    if (a.size() == n + n - 1 and pre.empty()) {
        // 长度合法且所有数字都放进来了
        int r = deal(a);
        if (r and status == 0)  // 出现合法解
            status = r;
        else if (status == 2 and r == 1)  // 出现无分数解
            status = r;
        return;
    }
    if (pre.size()) {
        int c = pre.back();
        a.push_back(c);
        pre.pop_back();
        dfs(a, pre, status, ch);
        a.pop_back();  // 回溯
        pre.push_back(c);
    }
    int num = a.size() - ch;
    if (ch < num - 1) {  // 可以加运算符
        rep(i, 0, 3) {   // 枚举加入的运算符
            a.push_back(opc[i]);
            dfs(a, pre, status, ch + 1);
            a.pop_back();  // 回溯
        }
    }
}

bool chk(vector<int> a) {
    int f = 0;
    do {  // 枚举数字出现顺序
        vector<int> l, r = a;
        dfs(l, r, f);
        if (f == 1) return 0;
    } while (next_permutation(a.begin(), a.end()));
    return f == 2;
}
int main() {
    cin >> n >> tar;
    if (n == 1) {
        cout << 0;
        return 0;
    } else if (n == 2) {  // 懒得写dfs
        rep(a, 1, 13) rep(b, a, 13) {
            vector<int> num{a, b};
            if (chk(num)) res.push_back(num);
        }
    } else if (n == 3) {
        rep(a, 1, 13) rep(b, a, 13) rep(c, b, 13) {
            vector<int> num = {a, b, c};
            if (chk(num)) res.push_back(num);
        }
    } else {
        rep(a, 1, 13) rep(b, a, 13) rep(c, b, 13) rep(d, c, 13) {
            vector<int> num = {a, b, c, d};
            if (chk(num)) res.push_back(num);
        }
    }
    cout << res.size() << '\n';
    for (vector<int> &v : res) {
        for (int &i : v) cout << i << ' ';
        cout << '\n';
    }
    return 0;
}

J

对于所有的间色三角形的三边,要么是黑白白,要么是黑黑白,也就是说,一个间色三角形,有两个异色角。

所以

#include <iostream>
using namespace std;
typedef long long ll;
const int N = 8007;
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;
}
bool edge[N][N];
int s1[N], s0[N];
int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n, seed;
    cin >> n >> seed;
    srand(seed);
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++)
            if (read()) // ij 黑边
                ++s1[i], ++s1[j];
            else        // ij 白边
                ++s0[i], ++s0[j];
    ll ans = 0;
    for (int i = 0; i < n; ++i) ans += s1[i] * s0[i]; // 异色角数量
    cout << (ll)n * (n - 1) * (n - 2) / 6 - ans / 2 << '\n';
    return 0;
}