Codeforces Round 908 (Div. 2)(A~E)(全是思维题)

1894A - Secret Sport 

        题意:A、B在玩博弈游戏。其中一局分为X个小局,赢下Y个大局之后获得最终胜利,结束游戏(X,Y未知)。给定一个只包含字母A和B的序列,分别代表了A获胜和B获胜。问最终胜利者是谁。

        思路:顺着题意来发现由于X,Y都未知,非常难判断谁在一局中赢了。但是逆着想会发现:当有人赢了Y个大局之后游戏直接结束了。因此赢得最后一小局的人也就赢得了游戏。

        

// Problem: A. Secret Sport
// Contest: Codeforces - Codeforces Round 908 (Div. 2)
// URL: https://codeforces.com/contest/1894/problem/0
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
void solve() 
{
	int n;
	cin>>n;
	string s;
	cin>>s;
	int cntA = 0 , cntB = 0;
	cout<>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

1894B - Two Out of Three  

        题意:给定一个长度为n的数组a,要求构造长度为n的只包含1 , 2 , 3的数组b,其中必须恰好满足以下三个中的两个条件:

1、\exists i , j (a[i] = a[j],b[i] = 1 , b[j] = 2)

2、\exists i , j (a[i] = a[j],b[i] = 1 , b[j] = 3)

3、\exists i , j (a[i] = a[j],b[i] = 2 , b[j] = 3)

        思路:若有三个数相等,他们下标在b数组上分别为1、2、3,那么将同时满足3个条件,不满足题意。因此对于相等的数而言,只能选其中一个条件进行满足。要求刚好满足两个条件,则至少需要两个不同的数在数组中存在相等的数。让他们分别满足两个条件,其余的数全部置1即可。

        

// Problem: Two Out of Three
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/B
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
void solve() 
{
	int n;
	cin>>n;
	int a[n];
	for(int i = 0 ; i < n ; i ++)
		cin>>a[i];
	mapmp;
	int ans[n];
	int flag = 0;
	for(int i = 0 ; i < n ; i ++){
		mp[a[i]]++;
		if(mp[a[i]] == 1){
			ans[i] = 1;
		}
		else if(mp[a[i]] == 2){
			if(flag == 0){
				ans[i] = 2;
				flag ++;
			}
			else if(flag == 1){
				ans[i] = 3;
				flag ++;
			}
			else{
				ans[i] = 1;
			}
		}
		else{
			ans[i] = 1;
		}
	}
	if(flag == 2){
		for(int i = 0 ; i < n ; i ++){
			cout<>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

 1894C - Anonymous Informant 

        题意:给定一个长度为n的数列b,要求构造出数列a,问是否能够用k次操作将a数组转化成b数组。操作步骤如下:

1、选定a数组中的一个点,要求a_{i} = i

2、将整个数组向左移动 i 位。(a_{1}a_{2}a_{3}a_{4}...a_{i}..a_{n} \rightarrow a_{i + 1}a_{i + 2}...a_{n}...a_{1}a_{2}a_{3}...a_{i}

        思路:同样考虑逆推,由于每次操作选定的a_{i}都会在操作之后变为数组的最后一位,那么b数组的最后一位就是最后一次操作选择的a_{i}。如此不断逆推k次,若期间出现了循环,则一定能够构造出a,使得k次操作后变为b。若期间出现了逆推得到的a_{i} > n的情况,则代表无法选择该数进行操作,则代表操作无法进行,则代表无法构造出a。

        

// Problem: Anonymous Informant
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/C
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
void solve() 
{
	int n , k;
	cin >> n >> k;
	int a[n];
	for(int i = 0 ; i < n ; i ++){
		cin>>a[i];
	}
	int left = 0;
	int st = n - 1;
	mapmp;
	mp[0] = 1;
	for(int i = 0 ; i < min(n , k) ; i ++){
		if(a[st - left] > n){
			cout<<"No\n";
			return;
		}
		left += a[st - left];
		left %= n;
		if(mp[left] == 0){
			mp[left]++;
		}
		else{
			cout<<"Yes\n";
			return;
		}
	}
	cout<<"Yes\n";
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

1894D - Neutral Tonality (最水D题)

        题意:给定数组a和b,要求将两个数组合并,其中a数组上数的相对位置无法改变。要求合并后的数组LIS(最长递增子序列)的长度最小。

        思路:直接贪心就行,甚至不用求LIS...要求LIS最小,那么b数组可以从大到小排序。然后考虑合并过程,两数组都从头开始合并,若此时a数组的数大于b数组的数,则将a数组的数放到前面,反之b数组的数放到前面(尽可能保证LIS = 1)。

        

// Problem: Neutral Tonality
// Contest: Codeforces
// URL: https://m1.codeforces.com/contest/1894/problem/D
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
const int INF = 1e9;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
int cmp1(int a , int b){
	return a > b;
}
struct Node{
    int val,num;
}z[maxn]; 
int T[maxn];
int NN;
void solve() 
{
	int n , m;
	cin>>n>>m;
	int a[n] , b[m];
	for(int i = 0 ; i >a[i];
	for(int i = 0; i < m ; i ++)
		cin>>b[i];
	sort(b ,b + m , cmp1);
	NN = m + n;
	int id = 1;
	for(int l = 0 , r = 0 ; l < n || r < m ;){
		if(l < n && r < m){
			if(a[l] > b[r]){
				z[id].num = id , z[id].val = a[l];
				l++;
			}
			else{
				z[id].num = id , z[id].val = b[r];
				r++;
			}
		}
		else if(l < n){
				z[id].num = id , z[id].val = a[l];
				l++;
		}
		else{
				z[id].num = id , z[id].val = b[r];
				r++;			
		}
		id++;
	}
	for(int i = 1 ; i <= NN ; i ++){
		cout<>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

1894E - Freedom of Choice  

        比赛时差点出来了,还是没想清楚。

        题意:定义一个multiset(多重集合)的价值为集合当中等于集合长度的元素的数量。现你有一个初始空multiset,接下来给定m个multiset,然后给定k , l , r。代表了multiset中有k个不同元素,且必须要选择[L,R]个元素放入到你的multiset中。然后一行给出了每个元素的值,再一行给出了每个元素的个数。求最终你的multiset的价值最小值。

        思路:首先考虑到元素的范围很大,而元素个数比较小,因此可以用离散化处理。求答案的过程可以遍历每个元素,然后计算最少能选多少个该元素。在处理每个元素 x 的过程中,显然不能再遍历每个multiset,于是我们可以将multiset中所有元素分为 x 和 非x两种。那么答案就是看总共选的x个元素当中有多少个非x元素。然后我们发现:由于每个multiset中最少选L个元素,那么就有可能出现必须要选择x元素的情况,因此需要记录一下至少选L个元素的情况下选中了多少个x元素min_x 。如此选完以后剩下的尽可能的不去选择x元素,然后发现:由于每个multiset中最多选择R个元素,因此并不是所有的非x元素都能被选中,因此还需要记录最多选R个元素的情况下有多少个非x元素没被选中 max_{!x}。因此最终选择了       min_x + max(0 ,(x - min_x - (sum - cnt_x - max_{!x})))

        

// Problem: E. Freedom of Choice
// Contest: Codeforces - Codeforces Round 908 (Div. 2)
// URL: https://codeforces.com/contest/1894/problem/E
// Memory Limit: 512 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include 
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pairpl;
priority_queue, greater >t;
priority_queue q;
LL gcd(LL a, LL b){
	return b > 0 ? gcd(b , a % b) : a;
}

LL lcm(LL a , LL b){
	return a / gcd(a , b) * b;
}
void solve() 
{
	LL l = 0 , r = 0;
	int n;
	cin>>n;
	LL max_cnt = 0;
	unordered_map< LL , LL > mp;
	unordered_map< LL , LL > minn;
	unordered_map< LL , LL > maxx;
	vectorv[n];
	vectorcnt[n];
	LL res_st = 0;
	for(int i = 0 ; i < n ; i ++){
		LL k , ll , rr;
		cin>>k>>ll>>rr;
		l += ll , r += rr;
		for(int j = 0 ; j < k ; j ++){
			LL x;
			cin>>x;
			v[i].pb(x);
		}
		LL cntt = 0;
		for(int j = 0 ; j < k ; j ++){
			LL x;
			cin>>x;
			cntt += x;
			cnt[i].pb(x);
			mp[v[i][j]] += x;
		}
		for(int j = 0 ; j < k ; j ++){
			maxx[v[i][j]] += max(1LL * 0 , cnt[i][j] - max(1LL * 0 ,(rr - (cntt - cnt[i][j]))));//在不可选中的数中有多少个x
			minn[v[i][j]] += max(1LL * 0 , ll - (cntt - cnt[i][j]));//至少选x个是v[i][j]
		}
		res_st += cntt - rr;//共有这么多个数是不可选的
		max_cnt += cntt;//共有max_cnt个数
	}	
	LL ans = 2e18;
	LL num_cnt = 0;
	for(auto it : mp){
		LL x = it.first;//选x个数
		if(x >= l && x <= r)//若不包含了[L , R]之内的所有数,答案可以为0
			num_cnt++;
		else
			continue;
		LL cntt = minn[x];//至少这么多个
		LL res = x - cntt ;//还需要这么多(全部拿其他数/拿完了再拿x)
		LL res_car = max_cnt - mp[x] - res_st + maxx[x];//最多能选这么多个不是x的数
		cntt += max(1LL * 0 , res - res_car);
		ans = min(ans , min(mp[x] , cntt));
	}
	if(r - l >= num_cnt){
		cout<<0<>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

        

你可能感兴趣的:(算法,数据结构,c++)