首页 > 其他分享 >CF906 div2

CF906 div2

时间:2023-11-15 16:36:05浏览次数:35  
标签:10 const int Solve CF906 Yes include div2

CF906 div2

A.Doremy's Paint 3

A.Doremy's Paint 3
题意
给出一个序列,可以随意打乱顺序,问最后能否使得所有相邻两个元素的和相等。
数据范围
多组数据,\(2 <= n <= 100 , 1 <= a_i <= 10^5\)
样例输入

5
2
8 9
3
1 1 2
4
1 1 4 5
5
2 3 3 3 3
4
100000 100000 100000 100000

样例输出

Yes
Yes
No
No
Yes

题解
有两种情况,一种是所有元素均相等;另一种是有两种元素交替出现,这就要求n为偶数时,两种元素个数相等,n为奇数时,两种元素的个数只差1.

#include<algorithm>
#include<iostream>
using namespace std;
const int N = 120;
int n;
int A[N];
void Solve()
{
	int val1 , val2 , cnt1 , cnt2 , flag;
	cin >> n;
	for(int i = 1 ; i <= n ; ++i)
		cin >> A[i];
	flag = 1;
	val1 = val2 = -1; cnt1 = cnt2 = 0;
	for(int i = 1 ; i <= n ; ++i)
	{
		if(val1 == -1)
		{
			val1 = A[i];
			cnt1 = 1;
		}
		else
		if(A[i] != val1)
		{
			if(val2 == -1)
			{
				val2 = A[i];
				cnt2 = 1;
			}
			else
			if(A[i] != val2)
			{
				flag = 0;
				break;
			}
			else
				cnt2++;
		}
		else
			cnt1++;
	}
	if(flag == 0)
		cout << "NO" << '\n';
	else
	if(val2 == -1 || max(cnt1 - cnt2 , cnt2 - cnt1) <= 1)
		cout << "YES" << '\n';
	else
		cout << "NO" << '\n';
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}

B.Qingshan Loves Strings

B.Qingshan Loves Strings
题意
给出一个大串和一个小串,均只含0或者1。
可以将小串插入到大串的任意位置任意多次(可以不操作)。
问能否使大串最终不会出现连续两个相同的元素。
数据范围
多组数据,\(1 <= T <= 2000 , 1 <= n , m <= 50\)
输入样例

5
1 1
1
0
3 3
111
010
3 2
111
00
6 7
101100
1010101
10 2
1001001000
10

输出样例

Yes
Yes
No
No
No

题解
先看大串是否本身已经满足要求,若是则结束,输出Yes。
再看小串是否满足要求,若不满足则结束,输出No。
然后看小串首尾是否相同,不同则结束,输出No。
小串满足要求且首尾相同时才能起到作用,假设小串首尾都是1,那么只能分开连续的0。
判断有无连续的1,若有则输出No,没有则输出Yes。
小串首尾是0,则同理。

#include<iostream>
using namespace std;
const int N = 66;
int n , m;
char s[N] , t[N];
void Solve()
{
	int flag;
	cin >> n >> m;
	cin >> (s + 1); cin >> (t + 1);
	flag = 1;
	for(int i = 1 ; i < n ; ++i)
		if(s[i] == s[i+1]) { flag = 0; break; }
	if(flag) { cout << "YES" << '\n'; return ; }
	flag = 1;
	for(int i = 1 ; i < m ; ++i)
		if(t[i] == t[i+1]) { flag = 0; break; }
	if((!flag) || (t[1] != t[m])) { cout << "NO" << '\n'; return ; }
	flag = 1;
	for(int i = 1 ; i < n ; ++i)
	{
		if(s[i] == s[i+1])
		{
			if(s[i] == t[1])
			{
				flag = 0;
				break;
			}
		}
	}
	if(flag) cout << "YES" << '\n'; else cout << "NO" << '\n';
	return ;
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}

C.Qingshan Loves Strings 2

C.Qingshan Loves Strings 2
题意
给出一个字符串,可以任意插入“01”,是否可以若干次操作之后使得\(a_i != a_{k - i + 1}\)对所有的i成立,k是字符串长度。
数据范围
多组数据,\(1 <= T <= 100 , 1 <= n <= 100\)
输入样例

6
2
01
3
000
4
1111
6
001110
10
0111001100
3
001

输出样例

0

-1
-1
2
6 7
1
10
-1

题解
如果0的个数不等于1的个数则无解。
因为0总是需要1去抵消,1总是需要0去抵消,而且操作插入的是"01"并不能改变01的个数之差。
对于\(a_l != a_r , l++ , r++\)
对于\(a_l == a_r \And a_l == 0\)则在r后插入01
对于\(a_l == a_r \And a_l == 1\)则在l前插入01
最坏的情况就是对于所有的<l,r>都需要操作,那就需要操作\(n / 2\)次,远不及300.
而且无解时,会不停增加新的操作,陷入死循环。
所以可以直接按照上述流程进行,如果操作数大于了300,那么一定是无解,如果没有死循环进而小于300,那么就一定是有解。

#include<iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
int n;
string s;
void Solve()
{
	string tmp;
	vector<int> V;
	cin >> n;
	cin >> s;
	if(n & 1) { cout << -1 << '\n'; return ; }
	for(int i = 0 ; i < s.length() - i - 1 ; ++i)
	{
		if(s[i] == s[s.length() - i - 1])
		{
			if(s[i] == '0')
			{
				V.push_back(s.length() - i);
				tmp = s.substr(0 , s.length() - i) + "01" + s.substr(s.length() - i , i);
				s = tmp;
			}
			else
			{
				tmp = s.substr(0 , i) + "01" + s.substr(i , s.length() - i);
				s = tmp;
				V.push_back(i);
			}
			if(V.size() > 300) break;
		}
	}
	if(V.size() <= 300)
	{
		cout << V.size() << '\n';
		for(auto x:V)
			cout << x << ' '; cout << '\n';
	}
	else
		cout << -1 << '\n';
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}
/*
6
2
01
3
000
4
1111
6
001110
10
0111001100
3
001
1010

*/

D.Doremy's Connecting Plan

D.Doremy's Connecting Plan
题意
有n个城市,城市i中有居民\(a_i\)个,现在想要将这n个城市连成一个联通块。
对于<i , j>如果满足\(\sum_{k\in S} a_i >= i*j*c\)则可以连边。
数据范围
多组数据,\(2 <= n <= 2*10^5 , 1 <= c <= 10 ^6,0 <= a_i <= 10^{12}\)
样例输入

7
4 10
0 20 15 10
2 1
1 1
5 1
0 1 0 4 199
5 2
1 1 3 1 1
5 5
5 6 1 10 2
5 1000000
1000000000000 1000000000000 1000000000000 1000000000000 1000000000000
3 1
0 0 2

样例输出

Yes
Yes
Yes
No
No
Yes
No

题解
要比较的代价是编号,那么编号1就是出去连边的最优选择。
那可考虑是不是有这么一种情况,第一条边不能连接1和其它,因为1号点的值太小,只能连接两个非1号点?
其实是不存在的。
如果第一条边不能链接1和else,那么对于所有的\(2 <= i <= n\)
满足\(a_1 + a_i <= i * c\),也就是\(a_i <= i*c - a_1\)
这样的话,就更不可能有\(x \neq 1,y \neq 1,a_x+a_y>=x*y*c\)
所以将2到n号点按照\(i * c - a_i\)从小到大排序,判断现有的联通块内的值是不是大于等于\(i * c - a_i\),是的话则加上\(a_i\),不是的话则不可行。

#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
using namespace std;
const int N = 2e5+10;
int n , c;
int p[N];
long long A[N];

bool cmp(const int &x , const int &y) { return 1ll * x * c - A[x] < 1ll * y * c - A[y]; }

void Solve()
{
	long long res = 0ll;
	cin >> n >> c;
	for(int i = 1 ; i <= n ; ++i)
		cin >> A[i] , p[i] = i;
	sort(p + 2 , p + 1 + n , cmp);
	res = A[1];
	for(int i = 2 ; i <= n ; ++i)
	{
		if(res >= 1ll * p[i] * c - A[p[i]])
			res += A[p[i]];
		else
		{
			cout << "NO" << '\n';
			return ;
		}
	}
	cout << "YES" << '\n';
}
int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}
/*
7
4 10
0 20 15 10
2 1
1 1
5 1
0 1 0 4 199
5 2
1 1 3 1 1
5 5
5 6 1 10 2
5 1000000
1000000000000 1000000000000 1000000000000 1000000000000 1000000000000
3 1
0 0 2
*/

E.Doremy's Drying Plan

E.Doremy's Drying Plan
题意
给出m个区间,范围都在1~n上,最多可以删去k个区间。
问1~n上最多能有多少个点没有被任何一个区间覆盖。
数据范围
多组数据,\(1 <= n <= 2*10^5 , 2 <= m <= 2*10^5,\)
简单版k=2,困难版\(2 <= k <= min(m , 10)\)
样例输入

6
2 3 2
1 2
1 2
1 1
5 3 2
1 3
2 4
3 5
10 6 4
1 5
6 10
2 2
3 7
5 8
1 4
100 6 5
1 100
1 100
1 100
1 100
1 100
1 100
1000 2 2
1 1
1 1
20 5 3
9 20
3 3
10 11
11 13
6 18

样例输出

1
2
6
0
1000
17

题解
简单版
两种情况,一种选择的区间没有交集,另一种有交集。
先算出每个点被多少个区间覆盖。
如果选择没有交集的,那么就找两个区间,区间中只被覆盖一次的点的个数最多(也就是只被所找的区间覆盖的点)。
如果选择有交集,那么交集部分统计被覆盖两次的点的个数,不交的部分还是统计覆盖一次的部分。
如果有交集的话,则有用的区间对至多有n个。讲区间按照左端点升序,右端点降序排列,对于区间i找到第一个右端点超出它的第一个区间j,那么<i,j>就是有用的,对于j之后的区间是相对i区间无用的。

#include<algorithm>
#include<iostream>
using namespace std;
const int N = 2e5+10;
int n , m , k;
int Sum[N] , Sum1[N] , Sum2[N];
struct Node{
	int l , r , val1 , val2;
}p[N];

bool cmp_val1(const Node &A , const Node &B) { return A.val1 > B.val1; }
bool cmp_pos (const Node &A , const Node &B) { return A.l == B.l ? A.r > B.r : A.l < B.l; }

void Solve()
{
	int res = 0 , Answer = 0;
	cin >> n >> m >> k;
	for(int i = 1 ; i <= m ; ++i)
		cin >> p[i].l >> p[i].r;
	for(int i = 0 ; i <= n + 1 ; ++i) Sum[i] = Sum1[i] = Sum2[i] = 0;
	for(int i = 1 ; i <= m ; ++i) Sum[p[i].l]++ , Sum[p[i].r+1]--;
	for(int i = 1 ; i <= n ; ++i) Sum[i] += Sum[i-1];
	for(int i = 1 ; i <= n ; ++i) if(Sum[i] == 0) res++;
	for(int i = 1 ; i <= n ; ++i) if(Sum[i] == 1) Sum1[i] = Sum1[i-1] + 1; else Sum1[i] = Sum1[i-1];
	for(int i = 1 ; i <= n ; ++i) if(Sum[i] == 2) Sum2[i] = Sum2[i-1] + 1; else Sum2[i] = Sum2[i-1];
	for(int i = 1 ; i <= m ; ++i)
		p[i].val1 = Sum1[p[i].r] - Sum1[p[i].l-1] ,
		p[i].val2 = Sum2[p[i].r] - Sum2[p[i].l-1] ;
	sort(p + 1 , p + 1 + m , cmp_val1);
	Answer = max(Answer , res + p[1].val1 + p[2].val1);
	sort(p + 1 , p + 1 + m , cmp_pos);
	for(int i = 1 ; i <= m ; ++i)
	{
		int j = i , l , r;
		while(j <= m && p[j].l >= p[i].l && p[j].r <= p[i].r) j++;
		for(int k = i + 1 ; k <= min(j , m) ; ++k)
		{
			l = max(p[i].l , p[k].l);
			r = min(p[i].r , p[k].r);
			Answer = max(Answer , res + p[i].val1 + p[k].val1 + max(Sum2[r] - Sum2[l-1] , 0));
		}
		i = j - 1;
	}
	cout << Answer << '\n';
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}

困难版
动态规划求解,设\(dp[i][j]\)表示到i为止,消除了j个区间,并且第i个位置目前没有区间覆盖的最大无覆盖的点的个数。
转移方程\(dp[i][j] = max\{1 + dp[t][j - d_t]\}\)
其中\(d_t\)表示\(t < l <= i <= r\)的区间个数。
\(d_t\)最多只有k种取值,每种取值对应一个第一维区间,所以就可以用O(k)的复杂度求出一个状态。
总的复杂度为O(n*k^2)

#include<algorithm>
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
const int N = 2e5+10 , inf = 1e8;
int n , m , k;
int St[11][N][18] , Visit[N];
vector<int> Add[N] , Dec[N];
struct Interval{ int l , r; }Inter[N];

inline void Update(int d , int p , int val)
{
	St[d][p][0] = max(St[d][p][0] , val);
	for(int i = 1 ; p - (1 << i) + 1 >= 0 ; ++i)
		St[d][p-(1<<i)+1][i] = 
		max(St[d][p-(1<<(i-1))+1][i-1] , St[d][p-(1<<i)+1][i-1]);
}

inline int Query(int d , int l , int r)
{
	int k = ceil(log2((r - l) / 2.0 + 1));
	return max(St[d][l][k] , St[d][r - (1 << k) + 1][k]);
}

void Init()
{
	for(int i = 0 ; i <= k ; ++i)
		for(int j = 0 ; j <= n ; ++j)
			for(int t = 0 ; t < 18 ; ++t)
				St[i][j][t] = -inf;
	for(int i = 0 ; i <= n + 1 ; ++i)
		Add[i].clear() , Dec[i].clear();
	for(int i = 0 ; i <= m ; ++i) Visit[i] = 0;	
}

bool cmp(int x , int y) { return Inter[x].l > Inter[y].l; }

int Solve()
{
	int cover , uncover , Answer , lst , pre;
	vector<int> tmp , cur;
	cin >> n >> m >> k;
	for(int i = 1 ; i <= m ; ++i)
		cin >> Inter[i].l >> Inter[i].r;
	Init();
	for(int i = 1 ; i <= m ; ++i)
		Add[Inter[i].l].push_back(i) ,
		Dec[Inter[i].r + 1].push_back(i);
	Update(0 , 0 , 0);
	cover = uncover = Answer = 0;
	for(int i = 1 ; i <= n ; ++i)
	{
		for(auto x:Add[i])
		{
			cover++;
			cur.push_back(x);
		}
		for(auto x:Dec[i])
		{
			cover--;
			Visit[x] = 1;
		}

		if(cover > k)
		{
			for(int j = 0 ; j <= k ; ++j)
				Update(j , i , -inf);
			continue;
		}

		tmp.clear();
		for(auto x:cur)
			if(!Visit[x]) tmp.push_back(x);
		cur = tmp;
		
		if(cur.empty())
		{
			for(int j = 0 ; j <= k ; ++j)
				Update(j , i , -inf);
			uncover++;
			continue;
		}

		sort(cur.begin() , cur.end() , cmp);
		if(Inter[cur[0]].l < i)
		{
			for(int j = 0 ; j <= k ; ++j)
			{
				int val = Query(j , Inter[cur[0]].l , i - 1);
				Answer = max(Answer , val + 1);
				Update(j , i , val + 1);
			}
		}
		else
		{
			for(int j = 0 ; j <= k ; ++j)
				Update(j , i , -inf);
		}

		lst = Inter[cur[0]].l - 1;
		for(int j = 0 ; j < min((int)cur.size() , k) ; ++j)
		{
			if(j + 1 != (int)cur.size() && Inter[cur[j]].l == Inter[cur[j+1]].l)
				continue;
			if(j + 1 == (int)cur.size())
				pre = 0;
			else
				pre = Inter[cur[j+1]].l;
			for(int g = j + 1 ; g <= k ; ++g)
			{
				int val = Query(g - (j + 1) , pre , lst);
				Answer = max(Answer , val + 1);
				Update(g , i , val + 1);
			}
			lst = pre - 1;
		}
	}
	cout << Answer + uncover << '\n';
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int T; cin >> T; while(T--) Solve();
	return 0;
}

标签:10,const,int,Solve,CF906,Yes,include,div2
From: https://www.cnblogs.com/sybs5968QAQ/p/17833828.html

相关文章

  • CF907 div2
    CF907div2A.SortingwithTwos题意给一个长度为n的序列,可以进行的操作是,选取一个i,令前\(2^i\)个元素减1,问若干次操作之后能否使得序列成为不降序列。数据范围多组数据\(1<=T<=10^4\),\(1<=n<=20\),\(0<=a_i<=1000\)输入样例851234556534496557......
  • cf908(div2)题解(补题)
    纪念这次div2让我上绿名,但还是有点遗憾,差一点就可以过三题超神了比赛链接cf908div2A这题是个骗人题,整个比赛会停下来就是一个人赢够了回合数,那么在谁这停下来就是谁赢了整个比赛,不用管每回合赢得规则。#include<iostream>usingnamespacestd;#include<string>intmain(){......
  • Codeforces Round 905 div2 F题
    记答案为\(ans_i\),表示从1到i次修改出现的字典序最小的数组a,\(c\)数组表示\(ans_i\)出现之后,所有修改的累加和。用一个vector存一下\(ans_i\)之后的所有修改。从1到q遍历每一次修改时,对\(c\)数组进行区间赋值操作,如果\(c\)数组中第一个不为0的数<0,那么\(ans_i\)加上\(c\)中的......
  • NOIP2023-div2模拟赛20 D. 数星星
    妙妙+经典题。难度:Hard。题意给定一棵\(n\)个结点的树,点有点权。树上有一些简单路径,编号分别为\(1,2,\cdots,m\)。有\(q\)次询问,每次询问查询编号在\([l,r]\)中的路径的并的点权和。题解考虑一个经典题:定一个数列,每次询问一个区间不同元素的和。这个问题是简单的,你......
  • 【codeforces】cf880div2 vp小结
    碎碎念多测要清空!清空从0开始循环!!!!!!!爆哭不知道因为初始化和清空罚了多少次了呜呜呜呜呜这次真的真的记得清空了,但是因为一直习惯下标从1开始所以导致for循环清空的时候a[0]没有清空A和B简简单单的两个签,但是C的难度就突然升高,补题的时候发现1700的时候真的...犹豫了一下要不要补......
  • CF906C题解
    可能更好的阅读体验大家好,我和DP有仇,所以我用猜结论的方法过了这道题。可能是这道题的一个全新思路,可能人自闭久了什么都能想出来(((upd:好像这也是官方题解思路,看来大家做题不太喜欢看CF官方题解(((首先考虑一个问题:如果这是一道构造题,怎么构造一组合法的解?在草稿纸上画了很久......
  • CF906C Party
    CF906CParty洛谷:CF906CPartyCodeforces:CF906CPartyProblem有\(n\)个人,给定他们的初始认识情况,每次操作可以选择一个人,让他当前认识的所有的人都相互认识。问至少操作几次使得所有人都相互认识,并给出任意合法且次数最少的操作方案。保证操作方案存在。Solution\(n\le......
  • 901DIV2 (A~D)
    901DIV2A~DA:大于等于\(a-1\)的贡献都是a-1.voidsolve(){intans=0;inta,b,n;cin>>a>>b>>n;ans+=b;for(inti=1;i<=n;i++){intx;cin>>x;if(x>=a)x=a-1;ans+=x;}cout<<......
  • 加训日记 Day5——codeforces round 899 再战div2
    Day5,9.25,codeforcesround899div2  ·事实证明自己的思维和手速都还不够快,晚上还晚来了一点  ·B题属实是,上来就想着并查集(菜鸡是这样的)然后发现不会写捏  ·思考了很久(看数据量)感觉是枚举暴力,但是又想不到怎么去枚举  ·一题遗憾离场  ·顺理成章的-26......
  • Codeforces Round 742 Div2 A-D题解
    CodeforcesRound742Div2A-D题解A.DominoDisaster这题就是说给出一些2x1tile,然后给出2xn的第一行构造,问第二行这个刚开始想着是啥dp,一看那么多人过了果断改思路,发现这题就是个模拟题,就是把U换成D,D换成U,L和R不影响,然后输出就行了代码#include<bits/stdc++.h>using......