CF1798

CF1798

随的div2构造场 真是想不出来

Showstopper

乱搞过了

我们钦定 \(b[n]\)\(a[n]\) 小 那么我们如果 \(b[i]>b[n]\) 的话 那么别无他法 只能换一下 如果换了也不行 直接判无解即可

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
const int N = 100 + 5;
const int inf = 0x3f3f3f3f;

int read()
{
	int f = 1 , x = 0;
	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 , a[N] , b[N] , tmp[2] , maxx;

signed main ()
{
	ios::sync_with_stdio(false);
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = read();
	while ( T -- )
	{
		n = read();
		generate ( a + 1 , a + n + 1 , read );
		generate ( b + 1 , b + n + 1 , read );
		if ( a[n] < b[n] ) swap ( a[n] , b[n] );
		for ( int i = 1 ; i <= n - 1 ; i ++ )
		{
			tmp[0] = a[i] , tmp[1] = b[i];
			if ( min ( tmp[0] , tmp[1] ) > b[n] ) { cout << "No" << endl; goto flg; }
			else if ( tmp[1] > b[n] ) swap ( a[i] , b[i] );
		}
		maxx = -inf;
		for ( int i = 1 ; i <= n ; i ++ ) maxx = max ( maxx , a[i] );
		if ( maxx != a[n] ) { cout << "No" << endl; goto flg; }
		cout << "Yes" << endl;
		flg:;
	}
	return 0;
}

Three Sevens

简单构造题 发现对于每一个人 只有最后一次买彩票中奖才有用

那么我们直接开 \(lst[i]\) 数组表示 \(i\) 人最后一次买彩票的场次 我们再开一个数组 \(cnt[i]\) 表示 \(i\) 天对应的中奖人编号

那么我们扫一遍值域为 \(cnt\) 数组赋值 最后扫一遍 \(cnt\) 数组判断无解或者输出方案即可

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
const int N = 5e4 + 5;
const int inf = 0x3f3f3f3f;

int read()
{
	int f = 1 , x = 0;
	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[N] , m , lst[N] , vis[N];

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = read();
	while ( T -- )
	{
		memset ( vis , 0 , sizeof vis );
		memset ( lst , 0 , sizeof lst );
		m = read();
		for ( int i = 1 ; i <= m ; i ++ )
		{
			n[i] = read();
			for ( int j = 1 ; j <= n[i] ; j ++ ) lst[read()] = i;
		}
		for ( int i = 1 ; i <= 50000 ; i ++ ) if ( lst[i] ) vis[lst[i]] = i;
		int flag = 1;
		for ( int i = 1 ; i <= m ; i ++ ) if ( !vis[i] ) { flag = 0; break; }
		if ( !flag ) cout << -1 << endl;
		else 
		{
			for ( int i = 1 ; i <= m ; i ++ ) cout << vis[i] << ' ';
			cout << endl;
		}
    }
	return 0;
}

Candy Store

想不到www

假设一个标签 \(tag\) 概括了 \(l\)\(r\) 种糖果的标签 则我们设 \(tag=c_{l\sim r}\)

\(\because c_i=d_i\times b_i\)

\(\therefore b_{l\sim r}\mid tag\)

\(\therefore \operatorname{lcm}(b_l,b_{l+1}\dots b_r)\mid tag\)

\(\because d_i\mid a_i\)

\(\therefore c_i\mid a_i\times b_i\)

\(\therefore tag\mid \gcd(a_l\times b_l,a_{l+1}\times b_{l+1}\dots a_r\times b_r)\)

\(\therefore \operatorname{lcm}(b_l,b_{l+1}\dots b_r)\mid \gcd(a_i\times b_i,a_{i+1}\times b_{i+1}\dots a_r\times b_r)\)

所以只要判断当前 \(\gcd\) 是否能被 \(\operatorname{lcm}\) 整除即可 如果不能 将 \(\gcd\) 更新成 \(a_i\times b_i\) \(\operatorname{lcm}\) 更新成 \(b_i\)

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define int long long 
const int N = 2e5 + 5;

int read()
{
	int f = 1 , x = 0;
	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 , a[N] , b[N] , ans;

int gcd ( int a , int b )
{
	if ( a % b == 0 ) return b;
	return gcd ( b , a % b );
}
int lcm ( int a , int b )
{
	return a * b / gcd ( a , b );
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = read();
	while ( T -- )
	{
		n = read();
		ans = 1;
		for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , b[i] = read();
		int gcdd = a[1] * b[1] , lcmm = b[1];
		for ( int i = 2 ; i <= n ; i ++ )
		{
			gcdd = gcd ( gcdd , a[i] * b[i] ) , lcmm = lcm ( lcmm , b[i] );
			if ( gcdd % lcmm ) lcmm = b[i] , gcdd = a[i] * b[i] , ++ ans;
		}
		cout << ans << endl;
	}
	return 0;
}

Shocking Arrangement

首先判断特例:如果全是 \(0\) 显然无解

对于其余的情况 我们维护新数列的前缀和 如果这个前缀和大于 \(0\) 那么我们在负数中选一个数加进序列中 如果前缀和小于等于 \(0\) 那么塞进去一个正数即可

这样对于每一个前缀和 我们都能保证它的取值范围在 \([min_{a[i]},max_{a[i]}]\) 中间 那么任意两个前缀和相减的绝对值最大值就一定在 \(max_{a[i]}-min_{a[i]}\) 之内 所以符合条件

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define int long long 
const int N = 3e5 + 5;

int read()
{
	int f = 1 , x = 0;
	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 , a[N] , b[N] , ans , flag , sum;
vector<int> zheng , fu;

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = read();
	while ( T -- )
	{
		flag = 0 , sum = 0;
		n = read();
		zheng.clear() , fu.clear();
		for ( int i = 1 ; i <= n ; i ++ ) flag |= ( a[i] = read() ) , a[i] >= 0 ? zheng.eb(a[i]) : fu.eb(a[i]);
		if ( !flag ) { cout << "No" << endl; continue; }
		cout << "Yes" << endl;
		cout << zheng[zheng.size()-1] << ' ';
		sum = zheng[zheng.size()-1];
		zheng.pop_back();
		for ( int i = 2 ; i <= n ; i ++ )
			if ( sum > 0 ) cout << fu[fu.size()-1] << ' ' , sum += fu[fu.size()-1] , fu.pop_back();
			else cout << zheng[zheng.size()-1] << ' ' , sum += zheng[zheng.size()-1] , zheng.pop_back();
		cout << endl;
	}
	return 0;
}

Multitest Generator

显然 操作数最多为两次 因为我们对于任意序列 \([1,n]\) 都可以通过将 \(a_1\) 固定为 \(1\) 而将 \(a_2\) 改为 \(n-2\) 来满足条件

对于 \(0\) 次操作 我们可以记录 \(f[i]\) 数组表示以 \(i\) 为末尾的后缀能构成的 \(test\) 个数

那么转移方程不难得到:

\[f_i=\begin{cases} 1,\qquad a_i=(n-i+1)-1\\ 0,\qquad i+a_i>n\>\operatorname{or}\>f_{i+a_i+1}=0\\ f_{i+a_i+1}+1,\qquad \text{otherwise} \end{cases}\]

\(i\) 位答案为 \(0\) 的充要条件就是 \(f_{i+1}\neq 0\)\(a_i=f_{i+1}\)

如果答案不为 \(0\) 考虑两种情况:

  1. \(f_{i+1}\neq 0\),但是 \(a_i\neq f_{i+1}\)
  2. \(f_{i+1}=0\)

对于第一种情况,令 \(a_i\leftarrow f_{i+1}\) 即可,操作数为 \(1\)

对于第二种情况,如果想要答案为 \(1\) 显然需要对 \(i+1\) 的后缀中的某一个数进行修改 使修改后 \(i+1\) 的后缀能构成 \(a_i\)\(test\)

\(g_i\) 表示在 \(i\) 的后缀中进行一次修改后 能得到的最多 \(test\)

这个修改有两种情况:

  1. 修改 \(a_i\)。这意味着我们可以随意改变第一个 \(test\) 的长度,也就是这第一个 \(test\) 可以接在后面的任意一个状态的前面,这种情况能得到的最大值为 \(\max\limits_{j=i+1}^nf_j+1\)
  2. 不修改 \(a_i\)。因为 \(a_{i+1}\)\(a_{i+a_i}\) 之间的数会被 \(a_i\) 所在的 \(test\) 所包含,所以只有修改 \(i+a_i+1\) 的后缀中的某个数才能有贡献。因此这种情况能得到的最大值为 \(g_{i+a_i+1}+1\)

那么 “ 对 \(i+1\) 的后缀中的某一个数进行修改后,\(i+1\) 的后缀能构成 \(a_i\)\(test\) ” 的充要条件就是 \(g_{i+1}\ge a_i\) 之所以是大于等于号 是因为我们可以将前面的一次 \(1\) 操作或者 \(2\) 操作改为修改 \(a_i\) 来吃掉一些 \(test\)

剩下的情况答案就是 \(2\)

清数组要清到 \(n+1\) (?)

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
const int N = 3e5 + 5;

int read()
{
	int f = 1 , x = 0;
	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 , a[N] , ans[N] , f[N] , g[N] , fmaxx[N];

void init()
{
	for ( int i = 1 ; i <= n + 1 ; i ++ ) f[i] = g[i] = ans[i] = fmaxx[i] = 0;
}

/*
3
7
3 1 3 1 2 1 1
4
1 2 1 7
4
2 7 1 1
*/

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
	int T = read();
	while ( T -- )
	{
		n = read();
		init();
		for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
		for ( int i = n ; i >= 2 ; i -- )
		{
			if ( i + a[i] == n ) f[i] = 1;
			else if ( i + a[i] < n && f[i+a[i]+1] ) f[i] = f[i+a[i]+1] + 1;
			fmaxx[i] = max ( f[i] , fmaxx[i+1] );
			if ( i + a[i] >= n ) g[i] = fmaxx[i+1] + 1;
			else g[i] = max ( fmaxx[i+1] , g[i+a[i]+1] ) + 1;
		}
		for ( int i = n - 1 ; i ; i -- )
		{
			if ( f[i+1] ) ans[i] = ( a[i] != f[i+1] );
			else if ( g[i+1] >= a[i] ) ans[i] = 1;
			else ans[i] = 2;
		}
		for ( int i = 1 ; i <= n - 1 ; i ++ ) cout << ans[i] << ' ';
		cout << endl;
	}
	return 0;
}
posted @ 2023-10-24 19:29  Echo_Long  阅读(646)  评论(0)    收藏  举报