2021牛客暑期多校夏令营第三场

前言

寻思好不容易实训结束了, 好好打一盘, 然而遗憾爆0… 也是因为后面懒得写了
后面看题的话, 几个签到题比较偏近公式题, 且需要数学知识比较丰富, 这就涉及到我的知识盲区了
在宿舍打的最后一场, 下场比赛就在回家的火车上了, 都交给yl了

B. Black and white

题意

给出一堆参数, 用这些参数构造了一个n * m的矩阵, 求如何把矩阵中所有数填黑, 特殊要求是如果一块方格周围有三个相邻的黑色方格, 那这个方格涂黑的代价为0

分析

比赛的时候想的bfs, 但是后续想了一下, 显然是错的, 赛后补题发现这是一道非常巧妙的最小生成树问题, 采用kruskal连接各个点, 用并查集来判断是否在一个区间内
最需要注意的一点在于, 用这种做法就相当于把横纵坐标看成需要相连的点, 把每个坐标上的数值当成把该横纵坐标连接需要的代价, 这是理解本题代码最重要的一部分

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;

const int N = 5010;

typedef struct node{
	int x, y;
	LL w;
	bool operator < (const node &W) const
    {
        return w < W.w;
    }
}Node;

int g[N][N];
Node A[N * N];
int a, b, c, d, n, m, p;
int cnt;
int f[N * N];
LL ans;
int dist[N * 2 + 10];

int find(int x)
{
	if (f[x] != x)	f[x] = find(f[x]);
	return f[x];
}

void kruskal()
{
	for (int i = 1; i <= n + m; i ++)	f[i] = i;
	
	int tot = 0;
	for (int i = 1; i <= n * m && tot < n + m - 1; i ++)
	{
		Node temp = A[i];
		int x = find(temp.x), y = find(temp.y + n);
		if (x != y)
		{
			f[x] = y;
			ans += temp.w;
			tot ++;
		}
	}
}


int main(void)
{
	cin >> n >> m >> a >> b >> c >> d >> p;
	A[0].w = a;
    for (int i = 1; i <= n; i ++)
	    for (int j = 1; j <= m; j ++)
	    {
	        int t = (i - 1) * m + j;
	        LL tt = (A[t - 1].w * A[t - 1].w * b + A[t - 1].w * c + d) % p;
	        A[t] = {i, j, tt};
	        g[i][j] = tt;
	    }
	
	sort(A + 1, A + n * m + 1);
	
	kruskal();
	
	cout << ans << endl;
	
	return 0;
}

总结

  1. 注意重载运算符的写法(新开cmp函数也行)
  2. 注意开LL, 虽说本题并没有说清数据范围到底是多大
  3. 最最重要的是理解这种, 将横纵坐标看成一副二分图, 将每个位置的权重看成这两个坐标相连所需要花费的代价(边权), 即以点代边, 以坐标代点, 非常巧妙

C. Minimum grid

题意

暂略

分析

据说是一道贪心公式题, 后续补题


E. Math

题意

求满足公式的数有多少对

分析

推公式的题目, 也有一些打表的技巧, 这类题做的我头疼, 就交给队友了, 后续不补


F. 24dian

题意

给出n个扑克, 每个扑克可以从1到13任选, 任意用加减乘除组合这4个数, 问是否能凑出m

分析

暴搜, 重点在于是否能枚举到每一种状态, 后续补题


J. Counting Triangles

题意

给出一段代码, 要求按照这个方式建边, 求出建好的图中有多少个同色三角形

分析

签到题, 但不理解公式就很难想到n ^ 2的做法, 比赛的时候能想到的都是n ^ 3的做法, 主要还是数学公式的推导, 只记录一种颜色的三角形相邻的边, 然后对于每一个减去异色的边即可, 由于是完全图, 最后用总数减去异色数量即可

代码

#include<cstdio>
#include<vector>
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;
bool edge[8005][8005];
int ve[8005][8005];
std::vector<int> a[8005];
std::vector<int> d[8005];

int main()
{
	int n, seed;
	scanf("%d%d", &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();
    		if (edge[i][j])
    		{
	    		a[i].push_back(j);
	    		a[j].push_back(i);
			}
		}
	
	long long sum = 0;
	for (int i = 0; i < n; i ++)
		sum += (a[i].size() * (n - a[i].size() - 1));
	
	printf("%lld\n", (long long)n * (n - 1) * (n - 2) / 6 - sum / 2);
    		
    
    
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值