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;
} 
京公网安备 11010502036488号