海亮 7.19 模拟赛

海亮 7.19 模拟赛

赛时感冒咳嗽极重 最后一小时在摆另一道题

本来以为只能拿\(40+0+0+30=70pts\)的 但是拿了\(85+0+0+30=115pts?\)

\(T1\)不太会算复杂度/\(kk\) 上来冲正解不成功就打了个暴力跑路()

\(T4\) \(30pts\)特判显然

有意义的一道题 成功让我抛弃了链前存图而改用\(vector\)

我们考虑类比三元环计数 先统计出来所有答案 再减去三元环的答案即可

\(e1\)存的是原图 \(e\)存的是三元组的图

\(buc[i]\)表示的是权值为\(i\)的点对个数 \(tmp[i]\)表示的是在当前节点的出点内 权值为\(i\)的儿子有多少个

这样就可以在遍历原图的时候统计答案了

因为三元环是不合法的 那么我们直接在新图中扫描所有三元环并减去贡献即可

统计\(max\):最后的时候从大到小扫描权值

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define int long long
const int N = 3e4 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}

int n , m , t , vis[N] , tmp[N] , u[N] , v[N] , a[N] , maxx = -1 , summ , buc[N] , maxval;

vector<int> e[N] , e1[N];

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	n = read() , m = read() , t = read();
	for ( int i = 1 ; i <= m ; i ++ ) u[i] = read() , v[i] = read() , e1[u[i]].push_back(v[i]) , e1[v[i]].push_back(u[i]);
	for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , maxval = max ( maxval , a[i] );
	for ( int i = 1 ; i <= m ; i ++ )
	{
		if ( e1[u[i]].size() > e1[v[i]].size() ) swap ( u[i] , v[i] );
		else if ( e1[u[i]].size() == e1[v[i]].size() && u[i] > v[i] ) swap ( u[i] , v[i] );
		e[u[i]].push_back(v[i]);
	}
	for ( int u = 1 ; u <= n ; u ++ )
	{
		int sum = 0;//出边到达的点的权值sum 
		for ( auto v : e1[u] )
		{
			summ += sum * a[v] , sum += a[v];
			for ( int i = 1 ; i <= maxval ; i ++ ) buc[i*a[v]] += tmp[i];
			tmp[a[v]] ++;
		}
		for ( auto v : e1[u] ) tmp[a[v]] = 0;
	}
	for ( int u = 1 ; u <= n ; u ++ )
	{
		for ( auto v : e[u] ) vis[v] = u;
		for ( auto v : e[u] ) for ( auto w : e[v] ) if ( vis[w] == u ) 
			buc[a[u]*a[v]] -- , buc[a[v]*a[w]] -- , buc[a[u]*a[w]] -- , summ -= a[u]*a[v] + a[u]*a[w] + a[v]*a[w];
	}//保证了每一个三元环只会被统计一次 
	for ( int i = maxval * maxval ; i ; i -- ) if ( buc[i] ) { maxx = i; break; }
	cout << ( ( t != 2 ) ? maxx : 0 ) << endl;
	cout << ( ( t != 1 ) ? ( summ << 1 ) : 0 ) << endl;
	return 0;
}

#D. 扫雷(landmine)

我们考虑先将\(5\times5\)的方格中填满"八卦图" 再推广到整张图

也就是下面的东西:

0 0 0 1 0

0 1 0 0 0

0 0 0 0 1

0 0 1 0 0

1 0 0 0 0

然后我们在前\(5\times 5\)个方格枚举题目中要求的\(n\times m\)矩阵的左上角 再暴力统计答案即可

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
const int N = 500 + 5;
const int inf = 0x3f3f3f3f;
int read ()
{
	int x = 0 , f = 1;
	char ch = cin.get();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
	return x * f;
}

int n , m , f[N][N] , cnt;
int st[5] = { 5 , 2 , 4 , 1 , 3 };

int calc ( int x , int y , int xx , int yy )
{
	int res = 0;
	for ( int i = x ; i <= xx ; i ++ )
		for ( int j = y ; j <= yy ; j ++ )
			res += f[i][j];
	return res;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	for ( int i = 1 ; i <= N ; i ++ )
		for ( int j = st[i%5] ; j <= N ; j += 5 )
			f[i][j] = 1;
	n = read() , m = read();
	int minn = inf , mini , minj;
	for ( int i = 1 ; i <= 5 ; i ++ )
		for ( int j = 1 ; j <= 5 ; j ++ )
			if ( calc ( i , j , i + n - 1 , j + m - 1 ) < minn ) minn = calc ( i , j , i + n - 1 , j + m - 1 ) , mini = i , minj = j;
	cout << minn << endl;
	for ( int i = mini ; i <= mini + n - 1 ; i ++ , cout.put(endl) )
		for ( int j = minj ; j <= minj + m - 1 ; j ++ )
			cout << f[i][j];
	return 0;
}
posted @ 2023-07-19 17:26  Echo_Long  阅读(11)  评论(0)    收藏  举报