B.Black and white
思维题, 只要想出来就好做了.
题目大意:
把一个矩阵全涂黑, 问最少需要多少花费,对一个2*2的矩阵的时候,有三个被涂黑了,那么第四个就黑了.每个元素的值就是涂黑的花费.
思路:
我们把行和列都看成一个点, 每个格子看成点之间的连线, 然后就得到了一个图. 在图上求最小生成树, 使得整个图能联通. 那就是所求值.
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5050;
int fa[N * 2];
ll n, m, a, b, c, d, p;
int find(int x) {
if (x == fa[x]) {
return x;
} else {
return fa[x] = find(fa[x]);
}
}
struct vv {
int u, v, w;
bool operator < (const vv h) const {
return h.w < w;
}
};
priority_queue<vv> pp;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> a >> b >> c >> d >> p;
ll tmp = a;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
tmp = (tmp * tmp * b + tmp * c + d) % p;
pp.push({ i, j + (int)n, (int)tmp});
}
}
for (int i = 1; i <= n + m; i++) fa[i] = i;
ll ans = 0, cot = 0;
while (!pp.empty()) {
vv tm1 = pp.top();
pp.pop();
// cout << tm1.u << " " << tm1.v << " " << tm1.w << endl;
int fu = find(tm1.u), fv = find(tm1.v);
if (fu == fv) continue;
ans += tm1.w;
cot++;
fa[fu] = fv;
if (cot == n + m - 1) break;
}
cout << ans << endl;
}
C. Minimum grid
最大匹配
题目大意:
给出每一行,每一列的最大值,然后给出能存放点的坐标, 然后求最后最小的和.
思路:
对于某个值, 我们要想最小化值, 就是尽量让相同值放在同一个地方, 所以我们就让相同的值作为点, 然后能用的格子作为边. 找最大匹配, 也就是尽量让相同的点匹配.
代码:
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define ctx cout << "xxxxxxx" << endl
const int K = 1e6 + 10;
const int N = 1e4 + 10;
vector<int> row[K], col[K];
bool mp[N][N];
int match[N], used[N];
vector<int> tmp[N];
ll n, m, k;
bool dfs(int pos)
{
for (auto i : tmp[pos])
{
if (used[i]) continue;
used[i] = 1;
if (!match[i] || dfs(match[i]))
{
match[i] = pos;
return 1;
}
}
return 0;
}
int main() {
cin >> n >> m >> k;
int x;
for (int i = 1; i <= n; i++) {
cin >> x;
row[x].push_back(i);
}
for (int i = 1; i <= n; i++) {
cin >> x;
col[x].push_back(i + n);
}
for (int i = 1; i <= m; i++) {
int y;
cin >> x >> y;
// if(x <= n && y <= n)
mp[x][y] = 1;
}
ll ans = 0;
for (int i = k; i >= 1; i--) {
if (row[i].size() == 0 && col[i].size() == 0) continue;
// vector<int> tmp[n+5];
for (int i = 1; i <= n; i++) tmp[i].clear();
for (auto r : row[i]) {
for (auto c : col[i]) {
if (mp[r][c - n]) tmp[r].push_back(c);
}
}
memset(match, 0, sizeof(match));
ll res = 0;
for (int i = 1; i <= n; i++) {
memset(used, 0, sizeof(used));
if (dfs(i)) res++;
}
ll maxx = row[i].size() + col[i].size() - res;
ans += maxx*i;
}
cout << ans << endl;
}
E. xy = k*(xx + yy), 1 <= x <= y <= n, 求满足的(x, y)对.
思路:
先暴力来一发, 打表找规律. 发现(x, x^3)一定满足, 后面出现了一些跳跃, 表现是y = pre_y * x ^ 2 - pre_x, x = pre_y;类似这样.
存住表, 然后排序, 二分找.
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
vector<ll> num;
void init(){
for(ll i = 2; i <= (1e6); i++){
ll tm1 = i*i*i, tm2 = i;
while(tm1 <= (1e18)){
num.push_back(tm1);
if(tm1 > (1e18+i)/(i*i)) break;
ll tm3 = tm1*i*i - tm2;
if(tm3 > 1e18) break;
tm2 = tm1;
tm1 = tm3;
}
}
sort(num.begin(), num.end());
}
int main(){
num.push_back(1);
init();
ll t;
cin >> t;
// for(int i = 0; i <= 100; i++) cout << num[i] << endl;
while(t--){
ll n;
cin >> n;
ll ans = lower_bound(num.begin(), num.end(), n+1) - num.begin();
cout << ans << endl;
}
}
F. 24 dian
暴力
题目:
四个数,加上 + , - , *, /, ‘(’ , ‘)’ 使之能得到m。必须包含分数。
思路:
暴力dfs,每次找两个数四则运算,一直到全部可能用完。
代码不会… 朋友给的
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const double eps = 1e-8;
int a[maxn], mp[14][14][14][14];
int n, m;
int cnt = 0;
vector<int>nows(4);
void dfs(vector<double>x, bool flag) {
if (x.size() == 1) {//计算结束得到一个值
if (abs(x[0] - m) < eps) {//该值是m
if (flag) {//如果出现过小数
if (mp[nows[0]][nows[1]][nows[2]][nows[3]] == 0)cnt++;//该数未被找到过则cnt++
mp[nows[0]][nows[1]][nows[2]][nows[3]]++;//记录该值被发现过一次
}
else {//没有出现过小数
if (mp[nows[0]][nows[1]][nows[2]][nows[3]] > 0)cnt--;//如果发现过该值是小数 cnt--
mp[nows[0]][nows[1]][nows[2]][nows[3]] = -INF;//标记该值可以没有出现过小数达到
}
}
return;
}
for (int i = 0;i < x.size();i++) {
vector<double>tmp1 = x;
double b; double a = x[i];//a取x的第i位
for (int j = i;j < tmp1.size() - 1;j++)//把x第i位移除得到tmp1
tmp1[j] = tmp1[j + 1];
tmp1.pop_back();
for (int j = 0;j < tmp1.size();j++) {
vector<double>tmp = tmp1;
b = tmp[j];//b取x的第j位
for (int k = j;k < tmp.size() - 1;k++)//把tem1第j位移除得到tmp
tmp[k] = tmp[k + 1];
tmp.pop_back();
//把a和b的计算结果放回数组 继续进行计算
tmp.push_back(a + b);
dfs(tmp, flag);
tmp.pop_back();
tmp.push_back(a - b);
dfs(tmp, flag);
tmp.pop_back();
tmp.push_back(b - a);
dfs(tmp, flag);
tmp.pop_back();
tmp.push_back(a * b);
dfs(tmp, flag);
tmp.pop_back();
if (abs(b - 0) > eps) {
tmp.push_back(a / b);
if (abs(round(a / b) - a / b) > eps) {
// cout << a << ' ' << b << endl;
dfs(tmp, 1);
}
else
dfs(tmp, flag);
tmp.pop_back();
}
if (abs(a - 0) > eps) {//a不是0就做“除以0 ”这个操作
tmp.push_back(b / a);
if (abs(round(b / a) - b / a) > eps) {//四舍五入的值和不四舍五入的值有差别则是小数
// cout << b << ' ' << a << endl;
dfs(tmp, 1);
}
else//否则是整数
dfs(tmp, flag);
tmp.pop_back();
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n >> m;
if (n <= 3)
{
cout << 0;
return 0;
}
for (int i = 1;i <= 13;i++)
for (int j = i;j <= 13;j++)
for (int k = j;k <= 13;k++)
for (int l = k;l <= 13;l++) {
nows[0] = i, nows[1] = j, nows[2] = k, nows[3] = l;
vector<double> tmp(4);
tmp[0] = i, tmp[1] = j, tmp[2] = k, tmp[3] = l;
dfs(tmp, 0);
}
cout << cnt << endl;
for (int i = 1;i <= 13;i++)
for (int j = i;j <= 13;j++)
for (int k = j;k <= 13;k++)
for (int l = k;l <= 13;l++)
if (mp[i][j][k][l] > 0)
cout << i << ' ' << j << ' ' << k << ' ' << l << endl;
}
J. Counting Triangles
思维题。
题目大意:
用给的程序生成边的颜色, 求颜色相同的三角形。
思路:
所有的可能减去不能的,就是答案。我们对每个点统计黑色和白色,那么这些边组成的三角形一定不能成。就是hei * bai。然后由于每个点都会遍历两次,所以最后结果除2.
代码
#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;
}
}
using namespace GenHelper;
using namespace std;
using ll = long long;
bool edge[8005][8005];
int n, seed;
void solve();
int main() {
cin >> n >> seed;
srand(seed);
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
edge[j][i] = edge[i][j] = read();
ll ans = 0, tmp = 0;
for(int i = 0; i < n; i++){
ll hei = 0, bai = 0;
for(int j = 0; j < n; j++){
if(j == i) continue;
if(edge[i][j]) hei++;
else bai++;
}
tmp += hei * bai;
}
ans = (ll)n*(n-1)*(n-2) / (3*2) - tmp/2;
cout << ans << endl;
return 0;
}