Loading

Deltix Round, Spring 2021 题解 A-E

Deltix Round, Spring 2021 题解 A-E

A Game of Life

题意

给定长度\(n\)的01串,其中的0每次有可能变成1,条件是这个0的左右有且仅有1个1

\(m\)次操作后的01串

\[2 \leq n \leq 10^3\\ 1 \leq m \leq 10^9 \]

分析

可以把这个操作变成1向左右拓展,两个1之间长度为奇数的话要么拓展到一半结束了,要么中间空一个,偶数可以填满

注意左右边界的情况

根据上述转化模拟即可

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll rd(){
	ll x;
	scanf("%lld",&x);
	return x;
}

const int maxn = 1e6 + 5;

void solve(){
	int n = rd();
	int m = rd();
	string s;
	cin >> s;
	vector<int> v;
	for(int i = 0;i < s.length();i++){
		if(s[i] == '1') v.push_back(i);
	}
	string ans;
	if(v.empty()) cout << s << '\n';
	else {
		int head = v[0];
		int mi = min(head,m);
		for(int i = 0;i < head - mi;i++) ans.push_back('0');
		for(int i = 0;i < mi;i++) ans.push_back('1');
		for(int i = 0;i < v.size() - 1;i++){
			ans.push_back('1');
			int tmp = v[i + 1] - v[i] - 1;
			int dis = tmp;
			tmp /= 2;
			if(1) {
				mi = min(tmp,m);
				for(int i = 0;i < mi;i++) ans.push_back('1');
				for(int i = 0;i < dis - 2 * mi;i++) ans.push_back('0');
				for(int i = 0;i < mi;i++) ans.push_back('1');
			}
		}
		ans.push_back('1');
		mi = min(m,n - 1 - v.back());
		for(int i = 0;i < mi;i++) ans.push_back('1');
		int len = ans.length();
		for(int i = 0;i < n - len;i++) ans.push_back('0');
		cout << ans << '\n';
	}
}

int main(){
	int T = rd();
	while(T--)
		solve();
}

B Lord of the Values

给定长度\(n\)的数组\(a\)

\(n\)为偶数

通过如下两个操作 要把每个元素变为当前数的相反数

  1. \(a_i =a_i + a_j\)
  2. \(a_j = a_j - a_i\)

注意条件\(i < j\)

\[2 \leq n \leq 10^3\\ 1 \leq a_i \leq 10^9 \]

分析

想想为什么给偶数,再结合这只是B题,往简单的想能够想到仅对两个数操作

只需要执行121212即可,操作次数\(3 * n\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll rd(){
	ll x;
	scanf("%lld",&x);
	return x;
}

const int maxn = 1e6 + 5;

void solve(){
	int n = rd();
	vector<int> v(n + 1);
	cout << n * 3 << '\n';
	for(int i = 1;i <= n;i++)
		v[i] = rd();
	for(int i = 1;i <= n;i += 2) {
		cout << "1 " << i << ' ' << i + 1 << '\n';
		cout << "2 " << i << ' ' << i + 1 << '\n';
		cout << "1 " << i << ' ' << i + 1 << '\n';
		cout << "2 " << i << ' ' << i + 1 << '\n';
		cout << "1 " << i << ' ' << i + 1 << '\n';
		cout << "2 " << i << ' ' << i + 1 << '\n';
	}	

}

int main(){
	int T = rd();
	while(T--) solve();
}

C Compression and Expansion

题意

制作一个目录一样的东西

目录规则:
要么在当前的后面加上".1"表示新开启一节

要么回到上一个并且让节数+1

1

1.1

1.1.1

1.1.2

1.2

1.2.1

2

2.1

2.2

形如这样的排版是合法的

现给出一组目录的最后一个数字,要求构造出一种排版方案,保证存在一种方案

\[1 \leq n \leq 10^3\\ 1 \leq a_i \leq n \]

分析

容易想到一种贪心策略,如果有新的1,那么直接无脑新开一节,加在末尾即可,如果不是1,为了保证合法,先前一定有一个数保证该数等于加入的数-1,这样只需要回退即可

于是这题就是变成了类似栈的模拟题

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll rd(){
	ll x;
	scanf("%lld",&x);
	return x;
}

const int maxn = 1e6 + 5;

void solve(){
	int n = rd();
	vector<int> v;
	vector<string> ans;
	int x = rd();
	ans.push_back("1");
	v.push_back(1);
	cout << ans[0] << '\n';
	for(int i = 2;i <= n;i++){
		int x = rd();
		if(x == 1) ans.push_back(".1"),v.push_back(1);
		else {
			while(!v.empty() && v.back() != x - 1) v.pop_back(),ans.pop_back();
			v.pop_back(),ans.pop_back();
			v.push_back(x);
			string tmp;
			while(x){
				tmp.push_back(x % 10 + '0');
				x /= 10;
			}
			if(!ans.empty()) tmp.push_back('.');
			reverse(tmp.begin(),tmp.end());
			ans.push_back(tmp);
		}
		for(int i = 0;i < ans.size();i++)
			cout << ans[i];
		puts("");
	}
}

int main(){
	int T = rd();
	while(T--) solve();
}

D Love-Hate

题意

集合中给出\(n\)个元素,每个元素表示长度为\(m\)的01串,保证每个01串1的个数不会超过15个

求出一个01串,这个01串至少是\(\lceil \frac{n}{2} \rceil\) 个元素的子集,且1的个数最多

\[1 \leq n \leq 2\times 10^5\\ 1 \leq p \leq m \leq 60\\ 1 \leq p \leq 15 \]

分析

这个01串一定是\(n\)个元素中的某个元素的子集

考虑随机选其中的若干个元素,由于至少要一半,那么随机选取的元素中一个答案元素都没有的可能性很小

因此枚举随机到的元素

考虑这个元素的子集,将这个元素和其他所有元素做与运算,会得到若干个状态,记录到cnt数组中,cnt数组表示这个元素能够作为答案的出现个数,因此还要做一次高维前缀和

然后就只要2进制枚举一下这个出现次数是否满足要求,是否能够更新答案即可

复杂度\(O(it * p * (2 ^p + n))\)

注意控制随机次数

代码

#include<bits/stdc++.h>
#define re register
using namespace std;
typedef long long ll;

int rd(){
	int x = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x;
}

const int maxn = 2e5 + 5;

const int MOD = 1e9 + 7;

char s[80];

ll a[maxn];
int b[(1 << 15) + 5];

int main(){
	int n = rd();
	int m = rd();
	int k = rd();
	ll ans = 0;
	int cnt_ans = 0;
	for(re int i = 0;i < n;i++){
		scanf("%s",s);
		a[i] = 0;
		for(int j = 0;j < m;j++)
			if(s[j] == '1') a[i] |= (1ll << j);
	}
	random_shuffle(a,a + n);
	for(re int it = 0;it < n && it < 130;it++){
		vector<int> pos;
		for(re int i = 0;i < m;i++)
			if((a[it] >> i) & 1) pos.push_back(i);
		k = (int)pos.size();
		for(re int i = 0;i < (1 << k);i++)
			b[i] = 0;
		for(re int i = 0;i < n;i++){
			int msk = 0;
			for(re int j = 0;j < k;j++)
				if((a[i] >> pos[j]) & 1) 
					msk |= (1 << j);
			b[msk]++;
		}
		for(re int i = 0;i < k;i++){
			for(re int msk = 0;msk < (1 << k);msk++){
				if((msk >> i) & 1) continue;
				b[msk] += b[msk | (1 << i)];
			}
		}
		for(re int msk = 0;msk < (1 << k);msk++){
			if(2 * b[msk] < n) continue;
			int cnt = 0;
			for(re int i = 0;i < k;i++)
				cnt += (msk >> i) & 1;
			if(cnt > cnt_ans) {
				cnt_ans = cnt;
				ans = 0;
				for(re int i = 0;i < k;i++)
					if((msk >> i) & 1) ans ^= (1ll << pos[i]);
			}	
		}
	}
	for(re int i = 0;i < m;i++)
		printf("%lld",(ans >> i) & 1);
}

E Crypto Lights

题意

给定\(n,k\)

长度为\(n\)的01串,每次会随机一个非\(1\)位置将\(0\)变为\(1\),当任意两个\(1\)之前的距离小于\(k - 1\)时结束,求结束时的1的个数的期望

\[2 \leq k \leq n \leq10^5\\ \]

分析

直接套用期望的公式

\[E(n) = \sum_{i=1}P(n \geq i) \]

可以把结束后的期望转化为结束前的期望

\[ans = E(n) + 1 \]

要求\(\geq i\)的概率,考虑当前有多少种情况,即有

\[n \times (n - 1) \times (n - 2)...\times (n - i + 1) \]

对于本身的放置情况,\(i\)个1把1分成$i -1 \(组,任意组之间的距离至少是\)k - 1$

此时定好的1的个数和中间0的个数加起来至少有\(n - i - (k - 1)(i - 1)\),剩下的随意放置。

只需要做隔板法即可

再考虑上顺序问题 即可得出现的情况总共有\(\tbinom{n - (k - 1)(i - 1)}{i} \times i!\)

因此

\[ans = 1 + \sum_{i=1} \tbinom{n - (k - 1)(i - 1)}{i} \times i! \times \frac{1}{\prod_{j=0}^{i-1}(n-j)} \]

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll rd(){
	ll x;
	scanf("%lld",&x);
	return x;
}

const int maxn = 1e5 + 5;

const int MOD = 1e9 + 7;

ll ksm(ll a,ll b = MOD - 2,ll m = MOD){
	ll ans = 1;
	ll base = a;
	while(b){
		if(b & 1) ans *= base,ans %= m;
		base *= base;
		base %= m;
		b >>= 1;
	}
	return ans;
}

ll fac[maxn],iv[maxn];

void solve(){
	int n = rd();
	int k = rd();
	k--;
	ll ans = 1;
	for(int i = 0;n - i * k >= i + 1;i++)
	   ans += ((ll)fac[n - i * k]) * iv[n - i * k - i - 1] % MOD * iv[n] % MOD * fac[n - i - 1] % MOD,ans %= MOD;
	cout << ans << '\n';	
}

int main(){
	fac[0] = 1;
	for(int i = 1;i < maxn;i++) fac[i] = (ll)fac[i - 1] * i % MOD;
	iv[maxn - 1] = ksm(fac[maxn - 1]);
	for(int i = maxn - 1;i;i--)
		iv[i - 1] = (ll)iv[i] * (i) % MOD;	
	int T = rd();
	while(T--) solve();
}
posted @ 2021-06-01 16:20  MQFLLY  阅读(69)  评论(0编辑  收藏  举报