垃圾ACMer的暑假训练220705

Codeforces Round #804 (Div. 2)思维题训练

Codeforces Round #804 (Div. 2) A. The Third Three Number Problem

原题指路:https://codeforces.com/contest/1699/problem/A

题意

t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据给定一个 n    ( 1 ≤ n ≤ 1 e 9 ) n\ \ (1\leq n\leq 1\mathrm{e}9) n  (1n1e9),求正整数 a , b , c   s . t .   ( a   x o r   b ) + ( b   x o r   c ) + ( c   x o r   a ) = n a,b,c\ s.t.\ (a\ \mathrm{xor}\ b)+(b\ \mathrm{xor}\ c)+(c\ \mathrm{xor}\ a)=n a,b,c s.t. (a xor b)+(b xor c)+(c xor a)=n.

思路

注意到 a   x o r   a = 0 , a   x o r   0 = a a\ \mathrm{xor}\ a=0,a\ \mathrm{xor}\ 0=a a xor a=0,a xor 0=a,不妨固定 b = 0 b=0 b=0,则 a + c + ( c   x o r   a ) + c = n a+c+(c\ \mathrm{xor}\ a)+c=n a+c+(c xor a)+c=n.

不妨再固定 c = 0 c=0 c=0,则 a + a = n a+a=n a+a=n,当 n n n为偶数时有解, a = n 2 a=\dfrac{n}{2} a=2n.

代码
int main() {
	CaseT{
		int n; cin >> n;
		if (n & 1) {
			cout << "-1" << endl;
			continue;
		}

		cout << n / 2 << " 0 0" << endl;
	}
}


Codeforces Round #804 (Div. 2) B. Almost Ternary Matrix

原题指路:https://codeforces.com/contest/1699/problem/B

题意

t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据给定 n , m    ( 2 ≤ n , m ≤ 50 ) n,m\ \ (2\leq n,m\leq 50) n,m  (2n,m50),求一个 n × m n\times m n×m 0 − 1 0-1 01矩阵$\ s.t.\ 对 每 个 元 素 对每个元素 (i,j) , 其 上 下 左 右 四 个 相 邻 的 元 素 ( 若 存 在 ) 恰 有 两 个 与 ,其上下左右四个相邻的元素(若存在)恰有两个与 ,()(i,j)$不同.

思路

构造题,考察是否有可以构造出大的解的小的单元.

观察样例 2 × 2 2\times 2 2×2的情况:

在这里插入图片描述

易想到能否将其复制一份放在右边作为 2 × 4 2\times 4 2×4的解,但事实上不行.

观察样例 2 × 4 2\times 4 2×4的情况:

在这里插入图片描述

易想到可将 2 × 2 2\times 2 2×2的单元镜像一下再放到右边.

猜想能否将 2 × 4 2\times 4 2×4的单元镜像一下再放到下面作为 4 × 4 4\times 4 4×4的解,显然可行.

在这里插入图片描述

考虑用 4 × 4 4\times 4 4×4的单元构造更大的解.显然将其复制一份放到右边即可.

可先打出一个 4 × 4 4\times 4 4×4的解 a n s ans ans,输出答案矩阵的元素 ( i , j ) (i,j) (i,j)时,只需输出 a n s [ i % 4 ] [ j % 4 ] ans[i\%4][j\%4] ans[i%4][j%4].

代码
string ans[4] = { "1001",
			   				  "0110",
				 					"0110",
								  "1001" };

int main() {
	CaseT{
		int n,m; cin >> n >> m;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++)
				cout << ans[i % 4][j % 4] << (j == m - 1 ? endl : ' ');
		}
	}
}


Codeforces Round #804 (Div. 2)

原题指路:https://codeforces.com/contest/1699/problem/C

题意

对两个 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1)的排列 a : { a 1 , ⋯   , a n } a:\{a_1,\cdots,a_n\} a:{a1,,an} b : { b 1 , ⋯   , b n } b:\{b_1,\cdots,b_n\} b:{b1,,bn},若对 ∀ [ l , r ]    ( 1 ≤ l ≤ r ≤ n ) \forall [l,r]\ \ (1\leq l\leq r\leq n) [l,r]  (1lrn),有 m e x ( [ a l , ⋯   , a r ] ) = m e x ( [ b l , ⋯   , b r ] ) \mathrm{mex}([a_l,\cdots,a_r])=\mathrm{mex}([b_l,\cdots,b_r]) mex([al,,ar])=mex([bl,,br]),则称 a a a b b b相似.

t    ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t  (1t1e4)组测试数据.每组测试数据给定一个 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1)的排列 a : { a 1 , ⋯   , a n } a:\{a_1,\cdots,a_n\} a:{a1,,an},求与 a a a相似的 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1)的排列的个数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.

思路

观察样例知,数 0 0 0的位置不变.枚举 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1),每次维护区间 [ l , r ] [l,r] [l,r]的端点和当前可选位置的个数 c n t cnt cnt,考察下一个数 i i i在排列 a a a中的下标 p o s pos pos,有两种情况:

①若 l ≤ p o s ≤ r l\leq pos\leq r lposr,则 i i i可放在区间 [ l , r ] [l,r] [l,r]中的任一位置而不改变 m e x ( [ l , r ] ) \mathrm{mex}([l,r]) mex([l,r]),此时 a n s ∗ = c n t ans*=cnt ans=cnt,放了一个数, c n t − − cnt-- cnt.

​ 如排列 x    x   1   x   3   x   0   x   x   x   2 x\ \ x\ 1\ x\ 3\ x\ 0\ x\ x\ x\ 2 x  x 1 x 3 x 0 x x x 2中,若维护以数 1 1 1、数 0 0 0分别为左、右端点的区间,则数 3 3 3在该区间内可任意放,而不改变该区间的 m e x = 0 \mathrm{mex}=0 mex=0.

②若 p o s < l pos<l pos<l,可选位置增加 [ p o s , l ] [pos,l] [pos,l]内的数的个数(不含 p o s pos pos l l l),即 c n t + = l − p o s − 1 cnt+=l-pos-1 cnt+=lpos1,并更新当前维护的区间为 [ p o s , r ] [pos,r] [pos,r].

③若 p o s > r pos>r pos>r,可选位置增加 [ r , p o s ] [r,pos] [r,pos]内的数的个数(不含 r r r p o s pos pos),即 c n t + = p o s − r − 1 cnt+=pos-r-1 cnt+=posr1,并更新当前维护的区间为 [ l , p o s ] [l,pos] [l,pos].

输入排列 a a a时记录 0 ∼ ( n − 1 ) 0\sim (n-1) 0(n1)中每个数 a [ i ] a[i] a[i] a a a中的下标 i d x [ a [ i ] ] idx[a[i]] idx[a[i]].

代码I
template<class T>
struct MOD_NUM {  // 数自动对MOD取模
	T num;
	static int MOD;

	T norm(T x) {  // 假设-MOD≤x<2*MOD
		if (x < 0) x += MOD;
		if (x >= MOD) x -= MOD;
		return x;
	}

	MOD_NUM(T _num = 0) :num(norm(_num)) {}
	T val()const { return num; }
	MOD_NUM inv()const { assert(num); return qpow(*this, MOD - 2, MOD); }  // MOD为素数

	MOD_NUM& operator-()const { return MOD_NUM(norm(MOD - num)); }
	MOD_NUM& operator*=(const MOD_NUM& rhs) { num = (ll)num * rhs.num % MOD; return *this; }
	MOD_NUM& operator+=(const MOD_NUM& rhs) { num = norm(num + rhs.num); return *this; }
	MOD_NUM& operator-=(const MOD_NUM& rhs) { num = norm(num - rhs.num); return *this; }
	MOD_NUM& operator/=(const MOD_NUM& rhs) { return *this *= rhs.inv(); }
	friend MOD_NUM operator*(const MOD_NUM& lhs, const MOD_NUM& rhs) { MOD_NUM res = lhs; res *= rhs; return res; }
	friend MOD_NUM operator+(const MOD_NUM& lhs, const MOD_NUM& rhs) { MOD_NUM res = lhs; res += rhs; return res; }
	friend MOD_NUM operator-(const MOD_NUM& lhs, const MOD_NUM& rhs) { MOD_NUM res = lhs; res -= rhs; return res; }
	friend MOD_NUM operator/(const MOD_NUM& lhs, const MOD_NUM& rhs) { MOD_NUM res = lhs; res /= rhs; return res; }
	friend bool operator==(const MOD_NUM& lhs, const MOD_NUM& rhs) { return lhs.val() == rhs.val(); }
	friend istream& operator>>(istream& stream, MOD_NUM& p) { stream >> p.num; return stream; }
	friend ostream& operator<<(ostream& stream, const MOD_NUM& p) { stream << p.val(); return stream; }
};
template<class T>
int MOD_NUM<T>::MOD = 1e9 + 7;

int main() {
	CaseT{
		int n; cin >> n;
		vi a(n), idx(n);  // 数、下标
		for (int i = 0; i < n; i++) {
			cin >> a[i];
			idx[a[i]] = i;
		}

		int l = idx[0], r = idx[0];  // 维护的区间初始为元素0的下标
		int cnt = 0;  // 当前可选的位置的个数

		MOD_NUM<int> ans = 1;
		for (int i = 1; i < n; i++) {  // 枚举数1到数(n-1)放的位置
			int pos = idx[i];  // 数i的位置
			if (l <= pos && pos <= r) {  // 当前位置在[l,r]内部(含边界)
				ans *= cnt;  // 任意放,不改变区间mex
				cnt--;  // 该位置放了数i
			}
			else {
				if (pos < l) {
					cnt += l - pos - 1;  // 更新可选位置个数
					l = pos;  // 更新所维护的区间
				}
				else {  // pos>r
					cnt += pos - r - 1;  // 更新可选位置个数
					r = pos;  // 更新所维护的区间
				}
			}
		}
		cout << ans << endl;
	}
}

代码II:省去维护 c n t cnt cnt
int main() {
	CaseT{
		int n; cin >> n;
		vi a(n), idx(n);  // 数、下标
		for (int i = 0; i < n; i++) {
			cin >> a[i];
			idx[a[i]] = i;
		}

		int l = idx[0], r = idx[0];  // 维护的区间初始为元素0的下标

		MOD_NUM<int> ans = 1;
		for (int i = 1; i < n; i++) {  // 枚举数1到数(n-1)放的位置
			int pos = idx[i];  // 数i的位置
			if (pos < l) l = pos;
			else if (pos > r) r = pos;
			else ans *= (r - l + 1 - i);  // l≤pos≤r
		}
		cout << ans << endl;
	}
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值