zoukankan      html  css  js  c++  java
  • 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 << '
    ';
    	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 << '
    ';
    	}
    }
    
    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 << '
    ';
    	for(int i = 1;i <= n;i++)
    		v[i] = rd();
    	for(int i = 1;i <= n;i += 2) {
    		cout << "1 " << i << ' ' << i + 1 << '
    ';
    		cout << "2 " << i << ' ' << i + 1 << '
    ';
    		cout << "1 " << i << ' ' << i + 1 << '
    ';
    		cout << "2 " << i << ' ' << i + 1 << '
    ';
    		cout << "1 " << i << ' ' << i + 1 << '
    ';
    		cout << "2 " << i << ' ' << i + 1 << '
    ';
    	}	
    
    }
    
    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] << '
    ';
    	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} ceil) 个元素的子集,且1的个数最多

    [1 leq n leq 2 imes 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 imes (n - 1) imes (n - 2)... imes (n - i + 1) ]

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

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

    只需要做隔板法即可

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

    因此

    [ans = 1 + sum_{i=1} binom{n - (k - 1)(i - 1)}{i} imes i! imes 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 << '
    ';	
    }
    
    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();
    }
    
  • 相关阅读:
    html基础进阶笔记
    程序员的自我提升
    过滤思路
    for循环
    jeesite在生成主子表代码的时候在eclipse里面没有子表代码
    java学习笔记2
    人性的弱点
    java学习笔记
    Percona Toolkit 安装使用
    mysql 中查询当天、本周,本月,上一个月的数据
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14837744.html
Copyright © 2011-2022 走看看