海亮 7.7 模拟赛

海亮7.7模拟赛

主打一个寄

\(T1\)\(30pts\)显然 然后开始罚坐 乐!

\(1h\)后发现\(T3\)可以玄学搜一波 加上固输\(35pts\) 虽然不是正经分也还不错了

打完\(T4\)暴力 最后\(T2\)怒打主席树并爆炸 我不好说

#A. 骰子游戏

\(30pts\)显然 那么我们的目标就是找六个数 使得这六个数任意两两异或起来都是\(k\)的倍数

那么显然有\(0\)\(k\) 那么为了互相没有影响(\(k\)小于等于60) 那么我们输出左移六位和十二位和它们互相异或的两个数即可

#include <bits/stdc++.h>
using namespace std;
const int N = 50;

inline int read ()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

int n , k;

signed main ()
{
	n = read() , k =read();
	cout << "Yes" << endl;
	for ( int i = 1 ; i <= n ; i ++ )
		cout << 0 << ' ' << k << ' ' << ( k << 6 ) << ' ' << ( ( k << 6 ) | k ) << ' ' << ( k << 12 ) << ' ' << ( ( k << 12 ) | k ) << endl;
	return 0;
}

#B. 裁剪彩带

\(dp[i]\)表示到\(i\)点的最大价值 那么\(dp[i]=max \{ dp[j]+mex(j,i) \}\)

观察到值域只有\(20\) 那么我们可以用一个二进制数记录区间内有没有这一个颜色 用\(st\)表来维护即可

我们可以预处理所有mex为0-21的情况 贪心地取满足mex为0-21的情况的最靠后的位置 来进行转移 贡献就是\(j\) 这可以用二分实现

最后对于方案的输出 我们记录\(pre[i]\)表示这一个状态由哪一个状态转移来的即可


#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
const int N = 5e5 + 5;

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;
}

vector<int> v;

int st[N][22] , n , a[N] , pre[N] , lg[N] , f[N];

int query ( int l , int r )
{
	int k = lg[r-l+1];
	return ( st[l][k] | st[r-(1<<k)+1][k] );
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	lg[0] = -1;
	n = read();
	for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , st[i][0] = ( 1 << a[i] );
	for ( int i = 1 ; i <= n ; i ++ ) lg[i] = lg[i>>1] + 1;
	for ( int j = 1 ; j <= 21 ; j ++ )
		for ( int i = 1 ; i + ( 1 << j - 1 ) <= n ; i ++ )
			st[i][j] = ( st[i][j-1] | st[i+(1<<j-1)][j-1] );
	for ( int i = 1 ; i <= n ; i ++ )
		for ( int j = 0 ; j <= 21 ; j ++ )
		{
			int temp = ( 1 << j ) - 1;
			if ( ( query ( 1 , i ) & temp ) != temp ) continue;
			int l = 1 , r = i;
			while ( l <= r )
			{
				if ( ( query ( mid , i ) & temp ) == temp ) l = mid + 1;
				else r = mid - 1;
			}
			//最后的l是不满足条件的第一个 r是满足条件的第一个 那么我们要从r的前一位开始转移 所以我们使用r 
			if ( f[i] < f[r-1] + j ) f[i] = f[r-1] + j , pre[i] = r - 1;
		}
	cout << f[n] << ' ';
	while ( n )
	{
		v.push_back(pre[n]+1);
		n = pre[n];
	}
	sort ( v.begin() , v.end() );a
	cout << v.size() << endl;
	for ( int i = 0 ; i < v.size() ; i ++ ) cout << v[i] << ' ';	
	return 0;
}


#C. 挑战NPC

最大流问题

将每一个点套路地拆成入点和出点 源点和出点连边 入点和汇点连边 然后跑最大流 我们就保证了每一个点的出边和入边均为\(1\)

如果最大流为\(0\) 那么是无解的情况

最后对于方案的输出 我们\(dfs\)一下 输出正向边为0的情况即可(实际上我不会/kel)

放上暴搜代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 25;

inline int read ()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

vector < int > a[N] , temp , ans[N][N];
int cntt[N] , vis[N];
int n , m , st;

int head[N] , cnt;
struct node { int to , nxt; } e[N<<2];
void add ( int u , int v ) { e[++cnt] = { v , head[u] } , head[u] = cnt; }

void dfs1 ( int u )
{
	if ( u == st && vis[st] ) { ans[st][++cntt[st]] = temp; return; }
	if ( vis[u] ) return;
	for ( int i = head[u] ; i ; i = e[i].nxt )
	{
		int v = e[i].to;
		vis[u] = 1;
		temp.push_back(u);
		dfs1 ( v );
		temp.pop_back();
		vis[u] = 0;
	}
}

void dfs ( int u )
{
	if ( u > n )
	{
		int flag = 1;
		for ( int i = 1 ; i <= n ; i ++ ) if ( !vis[i] ) flag = 0;
		if ( flag )
		{
			printf ( "YES\n" );
			for ( int i = 1 ; i <= n ; i ++ )
			{
				if ( a[i].size() ) 
				{
					printf ( "%d " , a[i].size() );
					for ( int j = 0 ; j < a[i].size() ; j ++ )
						printf ( "%d " , a[i][j] );
					putchar ( '\n' );
				}
			}
			exit(0);
		}
		return;
	}
	if ( vis[u] ) dfs ( u + 1 );
	st = u;
	dfs1 ( u );//将所有可能回路处理出来 
//	cout << "dfs1end" << endl;
//	for ( int i = 1 ; i <= cntt[st] ; i ++ , putchar('\n') )
//		for ( int j = 0 ; j < ans[st][i].size() ; j ++ )
//			printf ( "%d " , ans[st][i][j] ); 
//	cout << endl;
	for ( int i = 1 ; i <= cntt[st] ; i ++ )//一共有cntt[st]这些情况 
	{
		for ( int j = 0 ; j < ans[st][i].size() ; j ++ ) vis[ans[st][i][j]] = 1;
		a[st] = ans[st][i];
		dfs ( u + 1 );
		a[st].clear();
		for ( int j = 0 ; j < ans[st][i].size() ; j ++ ) vis[ans[st][i][j]] = 0;
	}	
}

signed main ()
{
	n = read() , m = read();
	if ( n > 20 ) { printf ( "NO" ); return 0; }
	for ( int i = 1 ; i <= m ; i ++ )
	{
		int u = read() , v = read();
		add ( u , v );
	}	
	dfs(1);
	printf ( "NO" );
	return 0;
}

posted @ 2023-07-07 16:14  Echo_Long  阅读(18)  评论(0编辑  收藏  举报